Replaced Logger usage with LOG_x (#548)
This commit is contained in:
committed by
GitHub
parent
ecad2248d9
commit
9d5993930d
@@ -3,7 +3,6 @@
|
||||
#include <Tactility/service/webserver/AssetVersion.h>
|
||||
|
||||
#include <Tactility/file/File.h>
|
||||
#include <Tactility/Logger.h>
|
||||
|
||||
#include <cJSON.h>
|
||||
#include <cstdio>
|
||||
@@ -12,9 +11,11 @@
|
||||
#include <memory>
|
||||
#include <esp_random.h>
|
||||
|
||||
#include <tactility/log.h>
|
||||
|
||||
namespace tt::service::webserver {
|
||||
|
||||
static const auto LOGGER = tt::Logger("AssetVersion");
|
||||
constexpr auto* TAG = "AssetVersion";
|
||||
constexpr auto* DATA_VERSION_FILE = "/system/app/WebServer/version.json";
|
||||
constexpr auto* SD_VERSION_FILE = "/sdcard/tactility/webserver/version.json";
|
||||
constexpr auto* DATA_ASSETS_DIR = "/system/app/WebServer";
|
||||
@@ -22,65 +23,65 @@ constexpr auto* SD_ASSETS_DIR = "/sdcard/tactility/webserver";
|
||||
|
||||
static bool loadVersionFromFile(const char* path, AssetVersion& version) {
|
||||
if (!file::isFile(path)) {
|
||||
LOGGER.warn("Version file not found: {}", path);
|
||||
LOG_W(TAG, "Version file not found: %s", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Read file content
|
||||
std::string content;
|
||||
{
|
||||
auto lock = file::getLock(path);
|
||||
lock->lock(portMAX_DELAY);
|
||||
|
||||
|
||||
FILE* fp = fopen(path, "r");
|
||||
if (!fp) {
|
||||
LOGGER.error("Failed to open version file: {}", path);
|
||||
LOG_E(TAG, "Failed to open version file: %s", path);
|
||||
lock->unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
char buffer[256];
|
||||
size_t bytesRead = fread(buffer, 1, sizeof(buffer) - 1, fp);
|
||||
bool readError = ferror(fp) != 0;
|
||||
fclose(fp);
|
||||
lock->unlock();
|
||||
|
||||
|
||||
if (readError) {
|
||||
LOGGER.error("Error reading version file: {}", path);
|
||||
LOG_E(TAG, "Error reading version file: %s", path);
|
||||
return false;
|
||||
}
|
||||
if (bytesRead == 0) {
|
||||
LOGGER.error("Version file is empty: {}", path);
|
||||
LOG_E(TAG, "Version file is empty: %s", path);
|
||||
return false;
|
||||
}
|
||||
buffer[bytesRead] = '\0';
|
||||
content = buffer;
|
||||
}
|
||||
|
||||
|
||||
// Parse JSON
|
||||
cJSON* json = cJSON_Parse(content.c_str());
|
||||
if (json == nullptr) {
|
||||
LOGGER.error("Failed to parse version JSON: {}", path);
|
||||
LOG_E(TAG, "Failed to parse version JSON: %s", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
cJSON* versionItem = cJSON_GetObjectItem(json, "version");
|
||||
if (versionItem == nullptr || !cJSON_IsNumber(versionItem)) {
|
||||
LOGGER.error("Invalid version JSON format: {}", path);
|
||||
LOG_E(TAG, "Invalid version JSON format: %s", path);
|
||||
cJSON_Delete(json);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
double versionValue = versionItem->valuedouble;
|
||||
if (versionValue < 0 || versionValue > UINT32_MAX) {
|
||||
LOGGER.error("Version out of valid range [0, {}]: {}", UINT32_MAX, path);
|
||||
LOG_E(TAG, "Version out of valid range [0, %u]: %s", (unsigned)UINT32_MAX, path);
|
||||
cJSON_Delete(json);
|
||||
return false;
|
||||
}
|
||||
version.version = static_cast<uint32_t>(versionValue);
|
||||
cJSON_Delete(json);
|
||||
|
||||
LOGGER.info("Loaded version {} from {}", version.version, path);
|
||||
|
||||
LOG_I(TAG, "Loaded version %u from %s", (unsigned)version.version, path);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -92,23 +93,23 @@ static bool saveVersionToFile(const char* path, const AssetVersion& version) {
|
||||
dirPath = dirPath.substr(0, lastSlash);
|
||||
if (!file::isDirectory(dirPath.c_str())) {
|
||||
if (!file::findOrCreateDirectory(dirPath.c_str(), 0755)) {
|
||||
LOGGER.error("Failed to create directory: {}", dirPath);
|
||||
LOG_E(TAG, "Failed to create directory: %s", dirPath.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create JSON
|
||||
cJSON* json = cJSON_CreateObject();
|
||||
if (json == nullptr) {
|
||||
LOGGER.error("Failed to create JSON object for version");
|
||||
LOG_E(TAG, "Failed to create JSON object for version");
|
||||
return false;
|
||||
}
|
||||
cJSON_AddNumberToObject(json, "version", version.version);
|
||||
|
||||
|
||||
char* jsonString = cJSON_Print(json);
|
||||
if (jsonString == nullptr) {
|
||||
LOGGER.error("Failed to serialize version JSON");
|
||||
LOG_E(TAG, "Failed to serialize version JSON");
|
||||
cJSON_Delete(json);
|
||||
return false;
|
||||
}
|
||||
@@ -126,12 +127,12 @@ static bool saveVersionToFile(const char* path, const AssetVersion& version) {
|
||||
success = (written == len);
|
||||
if (success) {
|
||||
if (fflush(fp) != 0) {
|
||||
LOGGER.error("Failed to flush version file: {}", path);
|
||||
LOG_E(TAG, "Failed to flush version file: %s", path);
|
||||
success = false;
|
||||
} else {
|
||||
int fd = fileno(fp);
|
||||
if (fd >= 0 && fsync(fd) != 0) {
|
||||
LOGGER.error("Failed to fsync version file: {}", path);
|
||||
LOG_E(TAG, "Failed to fsync version file: %s", path);
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
@@ -145,9 +146,9 @@ static bool saveVersionToFile(const char* path, const AssetVersion& version) {
|
||||
cJSON_Delete(json);
|
||||
|
||||
if (success) {
|
||||
LOGGER.info("Saved version {} to {}", version.version, path);
|
||||
LOG_I(TAG, "Saved version %u to %s", (unsigned)version.version, path);
|
||||
} else {
|
||||
LOGGER.error("Failed to write version file: {}", path);
|
||||
LOG_E(TAG, "Failed to write version file: %s", path);
|
||||
}
|
||||
|
||||
return success;
|
||||
@@ -180,15 +181,15 @@ bool hasSdAssets() {
|
||||
static bool copyDirectory(const char* src, const char* dst, int depth = 0) {
|
||||
constexpr int MAX_DEPTH = 16;
|
||||
if (depth >= MAX_DEPTH) {
|
||||
LOGGER.error("Max directory depth exceeded: {}", src);
|
||||
LOG_E(TAG, "Max directory depth exceeded: %s", src);
|
||||
return false;
|
||||
}
|
||||
LOGGER.info("Copying directory: {} -> {}", src, dst);
|
||||
|
||||
LOG_I(TAG, "Copying directory: %s -> %s", src, dst);
|
||||
|
||||
// Create destination directory
|
||||
if (!file::isDirectory(dst)) {
|
||||
if (!file::findOrCreateDirectory(dst, 0755)) {
|
||||
LOGGER.error("Failed to create destination directory: {}", dst);
|
||||
LOG_E(TAG, "Failed to create destination directory: %s", dst);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -216,7 +217,7 @@ static bool copyDirectory(const char* src, const char* dst, int depth = 0) {
|
||||
isDir = S_ISDIR(st.st_mode);
|
||||
isReg = S_ISREG(st.st_mode);
|
||||
} else {
|
||||
LOGGER.warn("Failed to stat entry, skipping: {}", srcPath);
|
||||
LOG_W(TAG, "Failed to stat entry, skipping: %s", srcPath.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -233,14 +234,14 @@ static bool copyDirectory(const char* src, const char* dst, int depth = 0) {
|
||||
|
||||
FILE* srcFile = fopen(srcPath.c_str(), "rb");
|
||||
if (!srcFile) {
|
||||
LOGGER.error("Failed to open source file: {}", srcPath);
|
||||
LOG_E(TAG, "Failed to open source file: %s", srcPath.c_str());
|
||||
copySuccess = false;
|
||||
return;
|
||||
}
|
||||
|
||||
FILE* tempFile = fopen(tempPath.c_str(), "wb");
|
||||
if (!tempFile) {
|
||||
LOGGER.error("Failed to create temp file: {}", tempPath);
|
||||
LOG_E(TAG, "Failed to create temp file: %s", tempPath.c_str());
|
||||
fclose(srcFile);
|
||||
copySuccess = false;
|
||||
return;
|
||||
@@ -254,7 +255,7 @@ static bool copyDirectory(const char* src, const char* dst, int depth = 0) {
|
||||
while ((bytesRead = fread(buffer.get(), 1, COPY_BUF_SIZE, srcFile)) > 0) {
|
||||
size_t bytesWritten = fwrite(buffer.get(), 1, bytesRead, tempFile);
|
||||
if (bytesWritten != bytesRead) {
|
||||
LOGGER.error("Failed to write to temp file: {}", tempPath);
|
||||
LOG_E(TAG, "Failed to write to temp file: %s", tempPath.c_str());
|
||||
fileCopySuccess = false;
|
||||
copySuccess = false;
|
||||
break;
|
||||
@@ -262,7 +263,7 @@ static bool copyDirectory(const char* src, const char* dst, int depth = 0) {
|
||||
}
|
||||
|
||||
if (fileCopySuccess && ferror(srcFile)) {
|
||||
LOGGER.error("Error reading source file: {}", srcPath);
|
||||
LOG_E(TAG, "Error reading source file: %s", srcPath.c_str());
|
||||
fileCopySuccess = false;
|
||||
copySuccess = false;
|
||||
}
|
||||
@@ -272,13 +273,13 @@ static bool copyDirectory(const char* src, const char* dst, int depth = 0) {
|
||||
// Flush and sync temp file before closing
|
||||
if (fileCopySuccess) {
|
||||
if (fflush(tempFile) != 0) {
|
||||
LOGGER.error("Failed to flush temp file: {}", tempPath);
|
||||
LOG_E(TAG, "Failed to flush temp file: %s", tempPath.c_str());
|
||||
fileCopySuccess = false;
|
||||
copySuccess = false;
|
||||
} else {
|
||||
int fd = fileno(tempFile);
|
||||
if (fd >= 0 && fsync(fd) != 0) {
|
||||
LOGGER.error("Failed to fsync temp file: {}", tempPath);
|
||||
LOG_E(TAG, "Failed to fsync temp file: %s", tempPath.c_str());
|
||||
fileCopySuccess = false;
|
||||
copySuccess = false;
|
||||
}
|
||||
@@ -292,7 +293,7 @@ static bool copyDirectory(const char* src, const char* dst, int depth = 0) {
|
||||
remove(dstPath.c_str());
|
||||
// Rename temp file to destination
|
||||
if (rename(tempPath.c_str(), dstPath.c_str()) != 0) {
|
||||
LOGGER.error("Failed to rename temp file {} to {}", tempPath, dstPath);
|
||||
LOG_E(TAG, "Failed to rename temp file %s to %s", tempPath.c_str(), dstPath.c_str());
|
||||
remove(tempPath.c_str());
|
||||
fileCopySuccess = false;
|
||||
copySuccess = false;
|
||||
@@ -303,13 +304,13 @@ static bool copyDirectory(const char* src, const char* dst, int depth = 0) {
|
||||
}
|
||||
|
||||
if (fileCopySuccess) {
|
||||
LOGGER.info("Copied file: {}", entry.d_name);
|
||||
LOG_I(TAG, "Copied file: %s", entry.d_name);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (!listSuccess) {
|
||||
LOGGER.error("Failed to list source directory: {}", src);
|
||||
LOG_E(TAG, "Failed to list source directory: %s", src);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -317,7 +318,7 @@ static bool copyDirectory(const char* src, const char* dst, int depth = 0) {
|
||||
}
|
||||
|
||||
bool syncAssets() {
|
||||
LOGGER.info("Starting asset synchronization...");
|
||||
LOG_I(TAG, "Starting asset synchronization...");
|
||||
|
||||
// Check if Data partition and SD card exist
|
||||
bool dataExists = hasDataAssets();
|
||||
@@ -325,26 +326,26 @@ bool syncAssets() {
|
||||
|
||||
// FIRST BOOT SCENARIO: Data has version 0, SD card is missing
|
||||
if (dataExists && !sdExists) {
|
||||
LOGGER.info("First boot - Data exists but SD card backup missing");
|
||||
LOGGER.warn("Skipping SD backup during boot - will be created on first settings save");
|
||||
LOGGER.warn("This avoids watchdog timeout if SD card is slow or corrupted");
|
||||
LOG_I(TAG, "First boot - Data exists but SD card backup missing");
|
||||
LOG_W(TAG, "Skipping SD backup during boot - will be created on first settings save");
|
||||
LOG_W(TAG, "This avoids watchdog timeout if SD card is slow or corrupted");
|
||||
return true; // Don't block boot - defer copy to runtime
|
||||
}
|
||||
|
||||
// NO SD CARD: Just ensure Data has default structure
|
||||
if (!sdExists) {
|
||||
LOGGER.warn("No SD card available - creating default Data structure if needed");
|
||||
LOG_W(TAG, "No SD card available - creating default Data structure if needed");
|
||||
if (!dataExists) {
|
||||
if (!file::findOrCreateDirectory(DATA_ASSETS_DIR, 0755)) {
|
||||
LOGGER.error("Failed to create Data assets directory");
|
||||
LOG_E(TAG, "Failed to create Data assets directory");
|
||||
return false;
|
||||
}
|
||||
AssetVersion defaultVersion(0); // Start at version 0 - SD card updates will be version 1+
|
||||
if (!saveDataVersion(defaultVersion)) {
|
||||
LOGGER.error("Failed to save default Data version");
|
||||
LOG_E(TAG, "Failed to save default Data version");
|
||||
return false;
|
||||
}
|
||||
LOGGER.info("Created default Data assets structure (version 0)");
|
||||
LOG_I(TAG, "Created default Data assets structure (version 0)");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -355,39 +356,39 @@ bool syncAssets() {
|
||||
bool hasSdVer = loadSdVersion(sdVersion);
|
||||
|
||||
if (!hasDataVer) {
|
||||
LOGGER.warn("No Data version.json - assuming version 0");
|
||||
LOG_W(TAG, "No Data version.json - assuming version 0");
|
||||
dataVersion.version = 0;
|
||||
if (!saveDataVersion(dataVersion)) {
|
||||
LOGGER.warn("Failed to save default Data version (non-fatal)");
|
||||
LOG_W(TAG, "Failed to save default Data version (non-fatal)");
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasSdVer) {
|
||||
LOGGER.warn("No SD version.json - assuming version 0");
|
||||
LOG_W(TAG, "No SD version.json - assuming version 0");
|
||||
sdVersion.version = 0;
|
||||
// DON'T save to SD during boot - defer to runtime
|
||||
LOGGER.warn("Skipping SD version.json creation during boot - will be created on first settings save");
|
||||
LOG_W(TAG, "Skipping SD version.json creation during boot - will be created on first settings save");
|
||||
}
|
||||
|
||||
LOGGER.info("Version comparison - Data: {}, SD: {}", dataVersion.version, sdVersion.version);
|
||||
LOG_I(TAG, "Version comparison - Data: %u, SD: %u", (unsigned)dataVersion.version, (unsigned)sdVersion.version);
|
||||
|
||||
if (sdVersion.version > dataVersion.version) {
|
||||
// Firmware update - copy SD -> Data
|
||||
LOGGER.info("SD card newer (v{} > v{}) - copying assets SD -> Data (firmware update)",
|
||||
sdVersion.version, dataVersion.version);
|
||||
LOG_I(TAG, "SD card newer (v%u > v%u) - copying assets SD -> Data (firmware update)",
|
||||
(unsigned)sdVersion.version, (unsigned)dataVersion.version);
|
||||
if (!copyDirectory(SD_ASSETS_DIR, DATA_ASSETS_DIR)) {
|
||||
LOGGER.error("Failed to copy assets from SD to Data");
|
||||
LOG_E(TAG, "Failed to copy assets from SD to Data");
|
||||
return false;
|
||||
}
|
||||
LOGGER.info("Firmware update complete - assets updated from SD card");
|
||||
LOG_I(TAG, "Firmware update complete - assets updated from SD card");
|
||||
} else if (dataVersion.version > sdVersion.version) {
|
||||
// User customization - backup Data -> SD
|
||||
LOGGER.warn("Data newer (v{} > v{}) - deferring SD backup to avoid boot watchdog",
|
||||
dataVersion.version, sdVersion.version);
|
||||
LOGGER.warn("SD backup will occur on first WebServer settings save");
|
||||
LOG_W(TAG, "Data newer (v%u > v%u) - deferring SD backup to avoid boot watchdog",
|
||||
(unsigned)dataVersion.version, (unsigned)sdVersion.version);
|
||||
LOG_W(TAG, "SD backup will occur on first WebServer settings save");
|
||||
return true; // Don't block boot - defer copy to runtime
|
||||
} else {
|
||||
LOGGER.info("Versions match (v{}) - no sync needed", dataVersion.version);
|
||||
LOG_I(TAG, "Versions match (v%u) - no sync needed", (unsigned)dataVersion.version);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <Tactility/settings/WebServerSettings.h>
|
||||
#include <Tactility/MountPoints.h>
|
||||
#include <Tactility/file/File.h>
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/lvgl/Statusbar.h>
|
||||
#include <Tactility/Mutex.h>
|
||||
|
||||
@@ -52,9 +51,11 @@
|
||||
#include <mbedtls/base64.h>
|
||||
#include <sstream>
|
||||
|
||||
#include <tactility/log.h>
|
||||
|
||||
namespace tt::service::webserver {
|
||||
|
||||
static const auto LOGGER = tt::Logger("WebServerService");
|
||||
constexpr auto* TAG = "WebServerService";
|
||||
|
||||
// Helper to convert chip model enum to human-readable string
|
||||
static const char* getChipModelName(esp_chip_model_t model) {
|
||||
@@ -142,14 +143,14 @@ static esp_err_t validateRequestAuth(httpd_req_t* request, bool& authPassed) {
|
||||
|
||||
std::string auth_header(auth_len + 1, '\0');
|
||||
if (httpd_req_get_hdr_value_str(request, "Authorization", auth_header.data(), auth_len + 1) != ESP_OK) {
|
||||
LOGGER.warn("Failed to read Authorization header");
|
||||
LOG_W(TAG, "Failed to read Authorization header");
|
||||
return sendUnauthorized(request, "Authorization required");
|
||||
}
|
||||
auth_header.resize(auth_len); // Remove null terminator from string length
|
||||
|
||||
// Check for "Basic " prefix
|
||||
if (auth_header.rfind("Basic ", 0) != 0) {
|
||||
LOGGER.warn("Authorization header is not Basic auth");
|
||||
LOG_W(TAG, "Authorization header is not Basic auth");
|
||||
return sendUnauthorized(request, "Basic authorization required");
|
||||
}
|
||||
|
||||
@@ -170,7 +171,7 @@ static esp_err_t validateRequestAuth(httpd_req_t* request, bool& authPassed) {
|
||||
reinterpret_cast<const unsigned char*>(base64_creds.c_str()),
|
||||
base64_creds.length());
|
||||
if (ret != 0) {
|
||||
LOGGER.warn("Failed to decode base64 credentials");
|
||||
LOG_W(TAG, "Failed to decode base64 credentials");
|
||||
return sendUnauthorized(request, "Invalid credentials format");
|
||||
}
|
||||
decoded.resize(actual_len);
|
||||
@@ -178,7 +179,7 @@ static esp_err_t validateRequestAuth(httpd_req_t* request, bool& authPassed) {
|
||||
// Parse username:password
|
||||
size_t colon_pos = decoded.find(':');
|
||||
if (colon_pos == std::string::npos) {
|
||||
LOGGER.warn("Invalid credentials format (no colon separator)");
|
||||
LOG_W(TAG, "Invalid credentials format (no colon separator)");
|
||||
return sendUnauthorized(request, "Invalid credentials format");
|
||||
}
|
||||
|
||||
@@ -189,7 +190,7 @@ static esp_err_t validateRequestAuth(httpd_req_t* request, bool& authPassed) {
|
||||
bool usernameMatch = secureCompare(username, settings.webServerUsername);
|
||||
bool passwordMatch = secureCompare(password, settings.webServerPassword);
|
||||
if (!usernameMatch || !passwordMatch) {
|
||||
LOGGER.warn("Invalid credentials for user '{}'", username);
|
||||
LOG_W(TAG, "Invalid credentials for user '%s'", username.c_str());
|
||||
return sendUnauthorized(request, "Invalid credentials");
|
||||
}
|
||||
|
||||
@@ -198,7 +199,7 @@ static esp_err_t validateRequestAuth(httpd_req_t* request, bool& authPassed) {
|
||||
}
|
||||
|
||||
bool WebServerService::onStart(ServiceContext& service) {
|
||||
LOGGER.info("Starting WebServer service...");
|
||||
LOG_I(TAG, "Starting WebServer service...");
|
||||
|
||||
// Register global instance
|
||||
g_webServerInstance.store(this);
|
||||
@@ -228,10 +229,10 @@ bool WebServerService::onStart(ServiceContext& service) {
|
||||
|
||||
// Start HTTP server only if enabled in settings (default: OFF to save memory)
|
||||
if (serverEnabled) {
|
||||
LOGGER.info("WebServer enabled in settings, starting HTTP server...");
|
||||
LOG_I(TAG, "WebServer enabled in settings, starting HTTP server...");
|
||||
setEnabled(true);
|
||||
} else {
|
||||
LOGGER.info("WebServer disabled in settings, NOT starting HTTP server (saves ~10KB RAM)");
|
||||
LOG_I(TAG, "WebServer disabled in settings, NOT starting HTTP server (saves ~10KB RAM)");
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
@@ -288,15 +289,15 @@ bool WebServerService::startApMode() {
|
||||
}
|
||||
|
||||
if (settings.wifiMode != settings::webserver::WiFiMode::AccessPoint) {
|
||||
LOGGER.info("Not in AP mode, skipping AP WiFi initialization");
|
||||
LOG_I(TAG, "Not in AP mode, skipping AP WiFi initialization");
|
||||
return true; // Not an error, just not needed
|
||||
}
|
||||
|
||||
LOGGER.info("Starting WiFi in Access Point mode...");
|
||||
LOG_I(TAG, "Starting WiFi in Access Point mode...");
|
||||
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
if (esp_wifi_init(&cfg) != ESP_OK) {
|
||||
LOGGER.error("esp_wifi_init() failed");
|
||||
LOG_E(TAG, "esp_wifi_init() failed");
|
||||
return false;
|
||||
}
|
||||
apWifiInitialized = true;
|
||||
@@ -304,14 +305,14 @@ bool WebServerService::startApMode() {
|
||||
// Create the AP network interface
|
||||
apNetif = esp_netif_create_default_wifi_ap();
|
||||
if (apNetif == nullptr) {
|
||||
LOGGER.error("esp_netif_create_default_wifi_ap() failed");
|
||||
LOG_E(TAG, "esp_netif_create_default_wifi_ap() failed");
|
||||
esp_wifi_deinit();
|
||||
apWifiInitialized = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (esp_wifi_set_mode(WIFI_MODE_AP) != ESP_OK) {
|
||||
LOGGER.error("esp_wifi_set_mode(AP) failed");
|
||||
LOG_E(TAG, "esp_wifi_set_mode(AP) failed");
|
||||
stopApMode();
|
||||
return false;
|
||||
}
|
||||
@@ -324,19 +325,19 @@ bool WebServerService::startApMode() {
|
||||
ip_info.netmask.addr = ipaddr_addr("255.255.255.0");
|
||||
|
||||
if (esp_netif_dhcps_stop(apNetif) != ESP_OK) {
|
||||
LOGGER.error("esp_netif_dhcps_stop() failed");
|
||||
LOG_E(TAG, "esp_netif_dhcps_stop() failed");
|
||||
stopApMode();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (esp_netif_set_ip_info(apNetif, &ip_info) != ESP_OK) {
|
||||
LOGGER.error("esp_netif_set_ip_info() failed");
|
||||
LOG_E(TAG, "esp_netif_set_ip_info() failed");
|
||||
stopApMode();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (esp_netif_dhcps_start(apNetif) != ESP_OK) {
|
||||
LOGGER.error("esp_netif_dhcps_start() failed");
|
||||
LOG_E(TAG, "esp_netif_dhcps_start() failed");
|
||||
stopApMode();
|
||||
return false;
|
||||
}
|
||||
@@ -354,36 +355,36 @@ bool WebServerService::startApMode() {
|
||||
if (settings.apOpenNetwork) {
|
||||
// User explicitly chose an open network
|
||||
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
|
||||
LOGGER.info("AP configured with OPEN authentication (user choice)");
|
||||
LOG_I(TAG, "AP configured with OPEN authentication (user choice)");
|
||||
} else if (settings.apPassword.length() >= 8 && settings.apPassword.length() <= 63) {
|
||||
wifi_config.ap.authmode = WIFI_AUTH_WPA2_PSK;
|
||||
strncpy(reinterpret_cast<char*>(wifi_config.ap.password), settings.apPassword.c_str(), sizeof(wifi_config.ap.password) - 1);
|
||||
wifi_config.ap.password[sizeof(wifi_config.ap.password) - 1] = '\0';
|
||||
LOGGER.info("AP configured with WPA2-PSK authentication");
|
||||
LOG_I(TAG, "AP configured with WPA2-PSK authentication");
|
||||
} else {
|
||||
if (!settings.apPassword.empty()) {
|
||||
LOGGER.warn("AP password invalid (must be 8-63 chars, got {}) - using OPEN mode", settings.apPassword.length());
|
||||
LOG_W(TAG, "AP password invalid (must be 8-63 chars, got %zu) - using OPEN mode", settings.apPassword.length());
|
||||
}
|
||||
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
|
||||
LOGGER.warn("AP configured with OPEN authentication (no password)");
|
||||
LOG_W(TAG, "AP configured with OPEN authentication (no password)");
|
||||
}
|
||||
|
||||
wifi_config.ap.max_connection = 4;
|
||||
wifi_config.ap.channel = settings.apChannel;
|
||||
|
||||
if (esp_wifi_set_config(WIFI_IF_AP, &wifi_config) != ESP_OK) {
|
||||
LOGGER.error("esp_wifi_set_config(AP) failed");
|
||||
LOG_E(TAG, "esp_wifi_set_config(AP) failed");
|
||||
stopApMode();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (esp_wifi_start() != ESP_OK) {
|
||||
LOGGER.error("esp_wifi_start() failed");
|
||||
LOG_E(TAG, "esp_wifi_start() failed");
|
||||
stopApMode();
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGGER.info("WiFi AP started - SSID: '{}', Channel: {}, IP: 192.168.4.1", settings.apSsid, settings.apChannel);
|
||||
LOG_I(TAG, "WiFi AP started - SSID: '%s', Channel: %u, IP: 192.168.4.1", settings.apSsid.c_str(), (unsigned)settings.apChannel);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -395,15 +396,15 @@ void WebServerService::stopApMode() {
|
||||
}
|
||||
err = esp_wifi_stop();
|
||||
if (err != ESP_OK && err != ESP_ERR_WIFI_NOT_STARTED) {
|
||||
LOGGER.warn("esp_wifi_stop() in cleanup: {}", esp_err_to_name(err));
|
||||
LOG_W(TAG, "esp_wifi_stop() in cleanup: %s", esp_err_to_name(err));
|
||||
}
|
||||
LOGGER.info("WiFi AP stopped");
|
||||
LOG_I(TAG, "WiFi AP stopped");
|
||||
|
||||
err = esp_wifi_set_mode(WIFI_MODE_STA);
|
||||
if (err != ESP_OK) {
|
||||
LOGGER.warn("esp_wifi_set_mode() in cleanup: {}", esp_err_to_name(err));
|
||||
LOG_W(TAG, "esp_wifi_set_mode() in cleanup: %s", esp_err_to_name(err));
|
||||
}
|
||||
LOGGER.info("Wifi mode set back to STA");
|
||||
LOG_I(TAG, "Wifi mode set back to STA");
|
||||
|
||||
apWifiInitialized = false;
|
||||
}
|
||||
@@ -428,7 +429,7 @@ bool WebServerService::startServer() {
|
||||
// Start AP mode WiFi if configured
|
||||
if (settings.wifiMode == settings::webserver::WiFiMode::AccessPoint) {
|
||||
if (!startApMode()) {
|
||||
LOGGER.error("Failed to start AP mode WiFi - HTTP server will not start");
|
||||
LOG_E(TAG, "Failed to start AP mode WiFi - HTTP server will not start");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -505,19 +506,19 @@ bool WebServerService::startServer() {
|
||||
|
||||
httpServer->start();
|
||||
if (!httpServer->isStarted()) {
|
||||
LOGGER.error("Failed to start HTTP server on port {}", settings.webServerPort);
|
||||
LOG_E(TAG, "Failed to start HTTP server on port %u", (unsigned)settings.webServerPort);
|
||||
httpServer.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGGER.info("HTTP server started successfully on port {}", settings.webServerPort);
|
||||
LOG_I(TAG, "HTTP server started successfully on port %u", (unsigned)settings.webServerPort);
|
||||
publish_event(this, WebServerEvent::WebServerStarted);
|
||||
|
||||
// Show statusbar icon
|
||||
if (statusbarIconId >= 0) {
|
||||
lvgl::statusbar_icon_set_image(statusbarIconId, LVGL_ICON_STATUSBAR_CLOUD);
|
||||
lvgl::statusbar_icon_set_visibility(statusbarIconId, true);
|
||||
LOGGER.info("WebServer statusbar icon shown ({} mode)",
|
||||
LOG_I(TAG, "WebServer statusbar icon shown (%s mode)",
|
||||
settings.wifiMode == settings::webserver::WiFiMode::AccessPoint ? "AP" : "Station");
|
||||
}
|
||||
|
||||
@@ -537,7 +538,7 @@ void WebServerService::stopServer() {
|
||||
stopApMode();
|
||||
}
|
||||
|
||||
LOGGER.info("HTTP server stopped");
|
||||
LOG_I(TAG, "HTTP server stopped");
|
||||
publish_event(this, WebServerEvent::WebServerStopped);
|
||||
|
||||
if (statusbarIconId >= 0) {
|
||||
@@ -550,7 +551,7 @@ void WebServerService::stopServer() {
|
||||
|
||||
|
||||
esp_err_t WebServerService::handleRoot(httpd_req_t* request) {
|
||||
LOGGER.info("GET / -> redirecting to /dashboard.html");
|
||||
LOG_I(TAG, "GET / -> redirecting to /dashboard.html");
|
||||
httpd_resp_set_status(request, "302 Found");
|
||||
httpd_resp_set_hdr(request, "Location", "/dashboard.html");
|
||||
return httpd_resp_send(request, nullptr, 0);
|
||||
@@ -722,7 +723,7 @@ static bool uriMatches(const char* uri, const char* route) {
|
||||
}
|
||||
|
||||
esp_err_t WebServerService::handleFileBrowser(httpd_req_t* request) {
|
||||
LOGGER.info("GET /filebrowser -> redirecting to /dashboard.html#files");
|
||||
LOG_I(TAG, "GET /filebrowser -> redirecting to /dashboard.html#files");
|
||||
httpd_resp_set_status(request, "302 Found");
|
||||
httpd_resp_set_hdr(request, "Location", "/dashboard.html#files");
|
||||
return httpd_resp_send(request, nullptr, 0);
|
||||
@@ -735,17 +736,17 @@ esp_err_t WebServerService::handleFsList(httpd_req_t* request) {
|
||||
if (qlen > 1) {
|
||||
std::unique_ptr<char[]> qbuf(new char[qlen]);
|
||||
if (httpd_req_get_url_query_str(request, qbuf.get(), qlen) == ESP_OK) {
|
||||
LOGGER.info("GET /fs/list raw query: {}", qbuf.get());
|
||||
LOG_I(TAG, "GET /fs/list raw query: %s", qbuf.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (!getQueryParam(request, "path", path) || path.empty()) path = "/";
|
||||
std::string norm = normalizePath(path);
|
||||
LOGGER.info("GET /fs/list decoded path: '{}' normalized: '{}'", path, norm);
|
||||
LOG_I(TAG, "GET /fs/list decoded path: '%s' normalized: '%s'", path.c_str(), norm.c_str());
|
||||
|
||||
// Allow root path for listing mount points
|
||||
if (!isAllowedBasePath(norm, true)) {
|
||||
LOGGER.warn("GET /fs/list - invalid path requested: '{}' normalized: '{}'", path, norm);
|
||||
LOG_W(TAG, "GET /fs/list - invalid path requested: '%s' normalized: '%s'", path.c_str(), norm.c_str());
|
||||
httpd_resp_set_type(request, "application/json");
|
||||
httpd_resp_sendstr(request, "{\"error\":\"invalid path\"}");
|
||||
return ESP_OK;
|
||||
@@ -811,7 +812,7 @@ esp_err_t WebServerService::handleFsDownload(httpd_req_t* request) {
|
||||
}
|
||||
std::string norm = normalizePath(path);
|
||||
if (!isAllowedBasePath(norm) || !file::isFile(norm)) {
|
||||
LOGGER.warn("GET /fs/download - not found or invalid path: '{}' normalized: '{}'", path, norm);
|
||||
LOG_W(TAG, "GET /fs/download - not found or invalid path: '%s' normalized: '%s'", path.c_str(), norm.c_str());
|
||||
httpd_resp_send_err(request, HTTPD_404_NOT_FOUND, "not found");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@@ -859,7 +860,7 @@ esp_err_t WebServerService::handleFsUpload(httpd_req_t* request) {
|
||||
if (qlen > 1) {
|
||||
std::unique_ptr<char[]> qbuf(new char[qlen]);
|
||||
if (httpd_req_get_url_query_str(request, qbuf.get(), qlen) == ESP_OK) {
|
||||
LOGGER.info("POST /fs/upload raw query: {}", qbuf.get());
|
||||
LOG_I(TAG, "POST /fs/upload raw query: %s", qbuf.get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -872,10 +873,10 @@ esp_err_t WebServerService::handleFsUpload(httpd_req_t* request) {
|
||||
char content_type[64] = {0};
|
||||
httpd_req_get_hdr_value_str(request, "Content-Type", content_type, sizeof(content_type));
|
||||
std::string norm = normalizePath(path);
|
||||
LOGGER.info("POST /fs/upload decoded path: '{}' normalized: '{}' Content-Length: {} Content-Type: {}", path, norm, (int)request->content_len, content_type[0] ? content_type : "(null)");
|
||||
LOG_I(TAG, "POST /fs/upload decoded path: '%s' normalized: '%s' Content-Length: %d Content-Type: %s", path.c_str(), norm.c_str(), (int)request->content_len, content_type[0] ? content_type : "(null)");
|
||||
|
||||
if (!isAllowedBasePath(norm)) {
|
||||
LOGGER.warn("POST /fs/upload - invalid path requested: '{}' normalized: '{}'", path, norm);
|
||||
LOG_W(TAG, "POST /fs/upload - invalid path requested: '%s' normalized: '%s'", path.c_str(), norm.c_str());
|
||||
httpd_resp_send_err(request, HTTPD_403_FORBIDDEN, "invalid path");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@@ -902,18 +903,18 @@ esp_err_t WebServerService::handleFsUpload(httpd_req_t* request) {
|
||||
// Timeout - retry with backoff
|
||||
timeout_retries++;
|
||||
if (timeout_retries >= MAX_TIMEOUT_RETRIES) {
|
||||
LOGGER.error("Upload recv timeout after {} retries", timeout_retries);
|
||||
LOG_E(TAG, "Upload recv timeout after %d retries", timeout_retries);
|
||||
fclose(fp);
|
||||
remove(norm.c_str()); // Clean up partial file
|
||||
httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "recv timeout");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
LOGGER.warn("Upload recv timeout, retry {}/{}", timeout_retries, MAX_TIMEOUT_RETRIES);
|
||||
LOG_W(TAG, "Upload recv timeout, retry %d/%d", timeout_retries, MAX_TIMEOUT_RETRIES);
|
||||
vTaskDelay(pdMS_TO_TICKS(100 * timeout_retries)); // Linear backoff
|
||||
continue;
|
||||
}
|
||||
if (ret <= 0) {
|
||||
LOGGER.error("Upload recv failed with error {}", ret);
|
||||
LOG_E(TAG, "Upload recv failed with error %d", ret);
|
||||
fclose(fp);
|
||||
remove(norm.c_str()); // Clean up partial file
|
||||
httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "recv failed");
|
||||
@@ -951,7 +952,7 @@ esp_err_t WebServerService::handleFsGenericGet(httpd_req_t* request) {
|
||||
if (uriMatches(uri, "/fs/list")) return handleFsList(request);
|
||||
if (uriMatches(uri, "/fs/download")) return handleFsDownload(request);
|
||||
if (uriMatches(uri, "/fs/tree")) return handleFsTree(request);
|
||||
LOGGER.warn("GET {} - not found in fs generic dispatcher", uri);
|
||||
LOG_W(TAG, "GET %s - not found in fs generic dispatcher", uri);
|
||||
httpd_resp_send_err(request, HTTPD_404_NOT_FOUND, "not found");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@@ -970,7 +971,7 @@ esp_err_t WebServerService::handleFsGenericPost(httpd_req_t* request) {
|
||||
if (uriMatches(uri, "/fs/delete")) return handleFsDelete(request);
|
||||
if (uriMatches(uri, "/fs/rename")) return handleFsRename(request);
|
||||
if (uriMatches(uri, "/fs/upload")) return handleFsUpload(request);
|
||||
LOGGER.warn("POST {} - not found in fs generic dispatcher", uri);
|
||||
LOG_W(TAG, "POST %s - not found in fs generic dispatcher", uri);
|
||||
httpd_resp_send_err(request, HTTPD_404_NOT_FOUND, "not found");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@@ -986,7 +987,7 @@ esp_err_t WebServerService::handleAdminPost(httpd_req_t* request) {
|
||||
|
||||
const char* uri = request->uri;
|
||||
if (strncmp(uri, "/admin/reboot", 13) == 0) return handleReboot(request);
|
||||
LOGGER.info("POST {} - not found in admin dispatcher", uri);
|
||||
LOG_I(TAG, "POST %s - not found in admin dispatcher", uri);
|
||||
httpd_resp_send_err(request, HTTPD_404_NOT_FOUND, "not found");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@@ -1019,7 +1020,7 @@ esp_err_t WebServerService::handleApiGet(httpd_req_t* request) {
|
||||
return handleApiScreenshot(request);
|
||||
}
|
||||
|
||||
LOGGER.warn("GET {} - not found in api dispatcher", uri);
|
||||
LOG_W(TAG, "GET %s - not found in api dispatcher", uri);
|
||||
httpd_resp_send_err(request, HTTPD_404_NOT_FOUND, "not found");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@@ -1040,7 +1041,7 @@ esp_err_t WebServerService::handleApiPost(httpd_req_t* request) {
|
||||
return handleApiAppsUninstall(request);
|
||||
}
|
||||
|
||||
LOGGER.warn("POST {} - not found in api dispatcher", uri);
|
||||
LOG_W(TAG, "POST %s - not found in api dispatcher", uri);
|
||||
httpd_resp_send_err(request, HTTPD_404_NOT_FOUND, "not found");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@@ -1058,13 +1059,13 @@ esp_err_t WebServerService::handleApiPut(httpd_req_t* request) {
|
||||
return handleApiAppsInstall(request);
|
||||
}
|
||||
|
||||
LOGGER.warn("PUT {} - not found in api dispatcher", uri);
|
||||
LOG_W(TAG, "PUT %s - not found in api dispatcher", uri);
|
||||
httpd_resp_send_err(request, HTTPD_404_NOT_FOUND, "not found");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t WebServerService::handleApiSysinfo(httpd_req_t* request) {
|
||||
LOGGER.info("GET /api/sysinfo");
|
||||
LOG_I(TAG, "GET /api/sysinfo");
|
||||
|
||||
std::ostringstream json;
|
||||
json << "{";
|
||||
@@ -1214,7 +1215,7 @@ esp_err_t WebServerService::handleApiSysinfo(httpd_req_t* request) {
|
||||
|
||||
// GET /api/apps - List installed apps
|
||||
esp_err_t WebServerService::handleApiApps(httpd_req_t* request) {
|
||||
LOGGER.info("GET /api/apps");
|
||||
LOG_I(TAG, "GET /api/apps");
|
||||
|
||||
auto manifests = app::getAppManifests();
|
||||
|
||||
@@ -1255,7 +1256,7 @@ esp_err_t WebServerService::handleApiApps(httpd_req_t* request) {
|
||||
|
||||
// POST /api/apps/run?id=xxx - Run an app
|
||||
esp_err_t WebServerService::handleApiAppsRun(httpd_req_t* request) {
|
||||
LOGGER.info("POST /api/apps/run");
|
||||
LOG_I(TAG, "POST /api/apps/run");
|
||||
|
||||
std::string appId;
|
||||
if (!getQueryParam(request, "id", appId) || appId.empty()) {
|
||||
@@ -1276,14 +1277,14 @@ esp_err_t WebServerService::handleApiAppsRun(httpd_req_t* request) {
|
||||
|
||||
app::start(appId);
|
||||
|
||||
LOGGER.info("[200] /api/apps/run {}", appId);
|
||||
LOG_I(TAG, "[200] /api/apps/run %s", appId.c_str());
|
||||
httpd_resp_sendstr(request, "ok");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// POST /api/apps/uninstall?id=xxx - Uninstall an app
|
||||
esp_err_t WebServerService::handleApiAppsUninstall(httpd_req_t* request) {
|
||||
LOGGER.info("POST /api/apps/uninstall");
|
||||
LOG_I(TAG, "POST /api/apps/uninstall");
|
||||
|
||||
std::string appId;
|
||||
if (!getQueryParam(request, "id", appId) || appId.empty()) {
|
||||
@@ -1293,7 +1294,7 @@ esp_err_t WebServerService::handleApiAppsUninstall(httpd_req_t* request) {
|
||||
|
||||
auto manifest = app::findAppManifestById(appId);
|
||||
if (!manifest) {
|
||||
LOGGER.info("[200] /api/apps/uninstall {} (app wasn't installed)", appId);
|
||||
LOG_I(TAG, "[200] /api/apps/uninstall %s (app wasn't installed)", appId.c_str());
|
||||
httpd_resp_sendstr(request, "ok");
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -1305,11 +1306,11 @@ esp_err_t WebServerService::handleApiAppsUninstall(httpd_req_t* request) {
|
||||
}
|
||||
|
||||
if (app::uninstall(appId)) {
|
||||
LOGGER.info("[200] /api/apps/uninstall {}", appId);
|
||||
LOG_I(TAG, "[200] /api/apps/uninstall %s", appId.c_str());
|
||||
httpd_resp_sendstr(request, "ok");
|
||||
return ESP_OK;
|
||||
} else {
|
||||
LOGGER.warn("[500] /api/apps/uninstall {}", appId);
|
||||
LOG_W(TAG, "[500] /api/apps/uninstall %s", appId.c_str());
|
||||
httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "uninstall failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@@ -1317,7 +1318,7 @@ esp_err_t WebServerService::handleApiAppsUninstall(httpd_req_t* request) {
|
||||
|
||||
// PUT /api/apps/install - Install an app from multipart form upload
|
||||
esp_err_t WebServerService::handleApiAppsInstall(httpd_req_t* request) {
|
||||
LOGGER.info("PUT /api/apps/install");
|
||||
LOG_I(TAG, "PUT /api/apps/install");
|
||||
|
||||
std::string boundary;
|
||||
if (!network::getMultiPartBoundaryOrSendError(request, boundary)) {
|
||||
@@ -1340,14 +1341,14 @@ esp_err_t WebServerService::handleApiAppsInstall(httpd_req_t* request) {
|
||||
|
||||
auto content_disposition_map = network::parseContentDisposition(content_headers);
|
||||
if (content_disposition_map.empty()) {
|
||||
LOGGER.warn("parseContentDisposition returned empty map for: {}", content_headers_data);
|
||||
LOG_W(TAG, "parseContentDisposition returned empty map for: %s", content_headers_data.c_str());
|
||||
httpd_resp_send_err(request, HTTPD_400_BAD_REQUEST, "invalid content disposition");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
auto filename_entry = content_disposition_map.find("filename");
|
||||
if (filename_entry == content_disposition_map.end()) {
|
||||
LOGGER.warn("filename not found in content disposition map");
|
||||
LOG_W(TAG, "filename not found in content disposition map");
|
||||
httpd_resp_send_err(request, HTTPD_400_BAD_REQUEST, "filename parameter missing");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@@ -1402,10 +1403,10 @@ esp_err_t WebServerService::handleApiAppsInstall(httpd_req_t* request) {
|
||||
|
||||
// Cleanup temp file
|
||||
if (!file::deleteFile(file_path)) {
|
||||
LOGGER.warn("Failed to delete temp file {}", file_path);
|
||||
LOG_W(TAG, "Failed to delete temp file %s", file_path.c_str());
|
||||
}
|
||||
|
||||
LOGGER.info("[200] /api/apps/install -> {}", file_path);
|
||||
LOG_I(TAG, "[200] /api/apps/install -> %s", file_path.c_str());
|
||||
httpd_resp_sendstr(request, "ok");
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -1425,7 +1426,7 @@ static const char* radioStateToJsonString(wifi::RadioState state) {
|
||||
|
||||
// GET /api/wifi - WiFi status
|
||||
esp_err_t WebServerService::handleApiWifi(httpd_req_t* request) {
|
||||
LOGGER.info("GET /api/wifi");
|
||||
LOG_I(TAG, "GET /api/wifi");
|
||||
|
||||
auto state = wifi::getRadioState();
|
||||
auto ip = wifi::getIp();
|
||||
@@ -1450,7 +1451,7 @@ esp_err_t WebServerService::handleApiWifi(httpd_req_t* request) {
|
||||
// GET /api/screenshot - Capture and return screenshot as PNG
|
||||
// Screenshots are saved to SD card root (if available) or /data with incrementing numbers
|
||||
esp_err_t WebServerService::handleApiScreenshot(httpd_req_t* request) {
|
||||
LOGGER.info("GET /api/screenshot");
|
||||
LOG_I(TAG, "GET /api/screenshot");
|
||||
|
||||
#if TT_FEATURE_SCREENSHOT_ENABLED
|
||||
// Determine save location: prefer SD card root if mounted, otherwise /data
|
||||
@@ -1471,7 +1472,7 @@ esp_err_t WebServerService::handleApiScreenshot(httpd_req_t* request) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
LOGGER.info("Screenshot will be saved to: {}", screenshot_path);
|
||||
LOG_I(TAG, "Screenshot will be saved to: %s", screenshot_path.c_str());
|
||||
|
||||
// LVGL's lodepng uses lv_fs which requires the "A:" prefix
|
||||
std::string lvgl_screenshot_path = lvgl::PATH_PREFIX + screenshot_path;
|
||||
@@ -1482,13 +1483,13 @@ esp_err_t WebServerService::handleApiScreenshot(httpd_req_t* request) {
|
||||
lvgl::unlock();
|
||||
|
||||
if (!success) {
|
||||
LOGGER.error("lv_screenshot_create failed for path: {}", lvgl_screenshot_path);
|
||||
LOG_E(TAG, "lv_screenshot_create failed for path: %s", lvgl_screenshot_path.c_str());
|
||||
httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "screenshot capture failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
LOGGER.info("Screenshot captured successfully");
|
||||
LOG_I(TAG, "Screenshot captured successfully");
|
||||
} else {
|
||||
LOGGER.error("Could not acquire LVGL lock within 100ms");
|
||||
LOG_E(TAG, "Could not acquire LVGL lock within 100ms");
|
||||
httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "could not acquire LVGL lock");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@@ -1514,7 +1515,7 @@ esp_err_t WebServerService::handleApiScreenshot(httpd_req_t* request) {
|
||||
httpd_resp_send_chunk(request, nullptr, 0);
|
||||
|
||||
// File is kept on storage (not deleted) for user access
|
||||
LOGGER.info("[200] /api/screenshot -> {}", screenshot_path);
|
||||
LOG_I(TAG, "[200] /api/screenshot -> %s", screenshot_path.c_str());
|
||||
return ESP_OK;
|
||||
#else
|
||||
httpd_resp_send_err(request, HTTPD_501_METHOD_NOT_IMPLEMENTED, "screenshot feature not enabled");
|
||||
@@ -1524,7 +1525,7 @@ esp_err_t WebServerService::handleApiScreenshot(httpd_req_t* request) {
|
||||
|
||||
esp_err_t WebServerService::handleFsTree(httpd_req_t* request) {
|
||||
|
||||
LOGGER.info("GET /fs/tree");
|
||||
LOG_I(TAG, "GET /fs/tree");
|
||||
|
||||
std::ostringstream json;
|
||||
json << "{";
|
||||
@@ -1569,7 +1570,7 @@ esp_err_t WebServerService::handleFsMkdir(httpd_req_t* request) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
std::string norm = normalizePath(path);
|
||||
LOGGER.info("POST /fs/mkdir requested: '{}' normalized: '{}'", path, norm);
|
||||
LOG_I(TAG, "POST /fs/mkdir requested: '%s' normalized: '%s'", path.c_str(), norm.c_str());
|
||||
if (!isAllowedBasePath(norm)) {
|
||||
httpd_resp_send_err(request, HTTPD_403_FORBIDDEN, "invalid path");
|
||||
return ESP_FAIL;
|
||||
@@ -1592,7 +1593,7 @@ esp_err_t WebServerService::handleFsDelete(httpd_req_t* request) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
std::string norm = normalizePath(path);
|
||||
LOGGER.info("POST /fs/delete requested: '{}' normalized: '{}'", path, norm);
|
||||
LOG_I(TAG, "POST /fs/delete requested: '%s' normalized: '%s'", path.c_str(), norm.c_str());
|
||||
if (!isAllowedBasePath(norm)) {
|
||||
httpd_resp_send_err(request, HTTPD_403_FORBIDDEN, "invalid path");
|
||||
return ESP_FAIL;
|
||||
@@ -1623,7 +1624,7 @@ esp_err_t WebServerService::handleFsRename(httpd_req_t* request) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
std::string norm = normalizePath(path);
|
||||
LOGGER.info("POST /fs/rename requested: '{}' normalized: '{}' -> newName: '{}'", path.c_str(), norm.c_str(), newName.c_str());
|
||||
LOG_I(TAG, "POST /fs/rename requested: '%s' normalized: '%s' -> newName: '%s'", path.c_str(), norm.c_str(), newName.c_str());
|
||||
if (!isAllowedBasePath(norm)) {
|
||||
httpd_resp_send_err(request, HTTPD_403_FORBIDDEN, "invalid path");
|
||||
return ESP_FAIL;
|
||||
@@ -1662,7 +1663,7 @@ esp_err_t WebServerService::handleFsRename(httpd_req_t* request) {
|
||||
int r = rename(norm.c_str(), target.c_str());
|
||||
if (r != 0) {
|
||||
int e = errno;
|
||||
LOGGER.warn("rename failed errno={} ({}) -> {} -> {}", e, strerror(e), norm, target);
|
||||
LOG_W(TAG, "rename failed errno=%d (%s) -> %s -> %s", e, strerror(e), norm.c_str(), target.c_str());
|
||||
// Return errno string to client to aid debugging
|
||||
std::string msg = std::string("rename failed: ") + strerror(e);
|
||||
httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, msg.c_str());
|
||||
@@ -1676,7 +1677,7 @@ esp_err_t WebServerService::handleFsRename(httpd_req_t* request) {
|
||||
|
||||
esp_err_t WebServerService::handleReboot(httpd_req_t* request) {
|
||||
|
||||
LOGGER.info("POST /reboot");
|
||||
LOG_I(TAG, "POST /reboot");
|
||||
httpd_resp_sendstr(request, "Rebooting...");
|
||||
|
||||
// Reboot after a short delay to allow response to be sent
|
||||
@@ -1695,7 +1696,7 @@ esp_err_t WebServerService::handleAssets(httpd_req_t* request) {
|
||||
}
|
||||
|
||||
const char* uri = request->uri;
|
||||
LOGGER.info("GET {}", uri);
|
||||
LOG_I(TAG, "GET %s", uri);
|
||||
|
||||
// Special case: serve favicon from system assets
|
||||
if (strcmp(uri, "/favicon.ico") == 0) {
|
||||
@@ -1721,7 +1722,7 @@ esp_err_t WebServerService::handleAssets(httpd_req_t* request) {
|
||||
fclose(fp);
|
||||
lock->unlock();
|
||||
httpd_resp_send_chunk(request, nullptr, 0);
|
||||
LOGGER.info("[200] {} (favicon)", uri);
|
||||
LOG_I(TAG, "[200] %s (favicon)", uri);
|
||||
return ESP_OK;
|
||||
}
|
||||
lock->unlock();
|
||||
@@ -1745,7 +1746,7 @@ esp_err_t WebServerService::handleAssets(httpd_req_t* request) {
|
||||
std::string dataPath = std::string("/system/app/WebServer") + requestedPath;
|
||||
|
||||
if (requestedPath == "/dashboard.html" && !file::isFile(dataPath.c_str())) {
|
||||
LOGGER.info("dashboard.html not found, serving default.html");
|
||||
LOG_I(TAG, "dashboard.html not found, serving default.html");
|
||||
}
|
||||
|
||||
// Try to serve from Data partition first
|
||||
@@ -1771,7 +1772,7 @@ esp_err_t WebServerService::handleAssets(httpd_req_t* request) {
|
||||
lock->unlock();
|
||||
|
||||
httpd_resp_send_chunk(request, nullptr, 0); // End of chunks
|
||||
LOGGER.info("[200] {} (from Data)", uri);
|
||||
LOG_I(TAG, "[200] %s (from Data)", uri);
|
||||
return ESP_OK;
|
||||
}
|
||||
lock->unlock();
|
||||
@@ -1800,14 +1801,14 @@ esp_err_t WebServerService::handleAssets(httpd_req_t* request) {
|
||||
lock->unlock();
|
||||
|
||||
httpd_resp_send_chunk(request, nullptr, 0); // End of chunks
|
||||
LOGGER.info("[200] {} (from SD)", uri);
|
||||
LOG_I(TAG, "[200] %s (from SD)", uri);
|
||||
return ESP_OK;
|
||||
}
|
||||
lock->unlock();
|
||||
}
|
||||
|
||||
// File not found
|
||||
LOGGER.warn("[404] {}", uri);
|
||||
LOG_W(TAG, "[404] %s", uri);
|
||||
httpd_resp_send_err(request, HTTPD_404_NOT_FOUND, "File not found");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@@ -1823,7 +1824,7 @@ void setWebServerEnabled(bool enabled) {
|
||||
instance->setEnabled(enabled);
|
||||
// Don't log here - startServer()/stopServer() already log the actual result
|
||||
} else {
|
||||
LOGGER.warn("WebServer service not available, cannot {}", enabled ? "start" : "stop");
|
||||
LOG_W(TAG, "WebServer service not available, cannot %s", enabled ? "start" : "stop");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user