From a19c55d783b4123e223365d0fa3bf5074c4eea93 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Thu, 23 Oct 2025 23:59:15 +0200 Subject: [PATCH] Create EspHttpClient --- .../Include/Tactility/network/EspHttpClient.h | 100 ++++++++++++++++++ Tactility/Include/Tactility/network/Http.h | 8 +- Tactility/Source/app/apphub/AppHubApp.cpp | 12 ++- Tactility/Source/network/Http.cpp | 63 +++++------ 4 files changed, 145 insertions(+), 38 deletions(-) create mode 100644 Tactility/Include/Tactility/network/EspHttpClient.h diff --git a/Tactility/Include/Tactility/network/EspHttpClient.h b/Tactility/Include/Tactility/network/EspHttpClient.h new file mode 100644 index 00000000..bdadd4ac --- /dev/null +++ b/Tactility/Include/Tactility/network/EspHttpClient.h @@ -0,0 +1,100 @@ +#pragma once + +#include + +namespace tt::network { + +class EspHttpClient { + + static constexpr auto* TAG = "EspHttpClient"; + + std::unique_ptr config = nullptr; + esp_http_client_handle_t client; + bool isOpen = false; + +public: + + ~EspHttpClient() { + if (isOpen) { + esp_http_client_close(client); + } + + if (client != nullptr) { + esp_http_client_cleanup(client); + } + } + + bool init(std::unique_ptr inConfig) { + TT_LOG_I(TAG, "init(%s)", inConfig->url); + assert(this->config == nullptr); + config = std::move(inConfig); + client = esp_http_client_init(config.get()); + return client != nullptr; + } + + bool open() { + assert(client != nullptr); + TT_LOG_I(TAG, "open()"); + auto result = esp_http_client_open(client, 0); + + if (result != ESP_OK) { + TT_LOG_E(TAG, "open() failed: %s", esp_err_to_name(result)); + return false; + } + + isOpen = true; + return true; + } + + bool fetchHeaders() const { + assert(client != nullptr); + TT_LOG_I(TAG, "fetchHeaders()"); + return esp_http_client_fetch_headers(client) >= 0; + } + + bool isStatusCodeOk() const { + assert(client != nullptr); + const auto status_code = getStatusCode(); + return status_code >= 200 && status_code < 300; + } + + int getStatusCode() const { + assert(client != nullptr); + const auto status_code = esp_http_client_get_status_code(client); + TT_LOG_I(TAG, "Status code %d", status_code); + return status_code; + } + + int getContentLength() const { + assert(client != nullptr); + return esp_http_client_get_content_length(client); + } + + int read(char* bytes, int size) const { + assert(client != nullptr); + TT_LOG_I(TAG, "read(%d)", size); + return esp_http_client_read(client, bytes, size); + } + + int readResponse(char* bytes, int size) const { + assert(client != nullptr); + TT_LOG_I(TAG, "readResponse(%d)", size); + return esp_http_client_read_response(client, bytes, size); + } + + bool close() { + assert(client != nullptr); + TT_LOG_I(TAG, "close()"); + return esp_http_client_close(client) == ESP_OK; + } + + bool cleanup() { + assert(client != nullptr); + TT_LOG_I(TAG, "cleanup()"); + const auto result = esp_http_client_cleanup(client); + client = nullptr; + return result == ESP_OK; + } +}; + +} diff --git a/Tactility/Include/Tactility/network/Http.h b/Tactility/Include/Tactility/network/Http.h index bb482342..64305e70 100644 --- a/Tactility/Include/Tactility/network/Http.h +++ b/Tactility/Include/Tactility/network/Http.h @@ -5,6 +5,12 @@ namespace tt::network::http { -void download(const std::string& url, const std::string& certFilePath, const std::string &downloadFilePath); +void download( + const std::string& url, + const std::string& certFilePath, + const std::string &downloadFilePath, + std::function onSuccess, + std::function onError +); } diff --git a/Tactility/Source/app/apphub/AppHubApp.cpp b/Tactility/Source/app/apphub/AppHubApp.cpp index 533072a0..41a985cd 100644 --- a/Tactility/Source/app/apphub/AppHubApp.cpp +++ b/Tactility/Source/app/apphub/AppHubApp.cpp @@ -104,7 +104,17 @@ class AppHubApp final : public App { lv_obj_remove_flag(refreshButton, LV_OBJ_FLAG_HIDDEN); auto download_path = std::format("{}/app_hub.json", getTempPath()); - network::http::download(getAppsJsonUrl(), "/system/certificates/WE1.pem", download_path); + network::http::download( + getAppsJsonUrl(), + "/system/certificates/WE1.pem", + download_path, + [] { + TT_LOG_I(TAG, "Request OK"); + }, + [] { + TT_LOG_E(TAG, "Request error"); + } + ); } public: diff --git a/Tactility/Source/network/Http.cpp b/Tactility/Source/network/Http.cpp index 13430831..4367094a 100644 --- a/Tactility/Source/network/Http.cpp +++ b/Tactility/Source/network/Http.cpp @@ -2,19 +2,26 @@ #include #include #include +#include namespace tt::network::http { constexpr auto* TAG = "HTTP"; -void download(const std::string& url, const std::string& certFilePath, const std::string &downloadFilePath) { +void download( + const std::string& url, + const std::string& certFilePath, + const std::string &downloadFilePath, + std::function onSuccess, + std::function onError +) { TT_LOG_I(TAG, "Download %s to %s", url.c_str(), downloadFilePath.c_str()); - getMainDispatcher().dispatch([url, certFilePath, downloadFilePath] { + getMainDispatcher().dispatch([url, certFilePath, downloadFilePath, onSuccess, onError] { + TT_LOG_I(TAG, "Loading certificate"); auto certificate = file::readString(certFilePath); auto certificate_length = strlen(reinterpret_cast(certificate.get())) + 1; - TT_LOG_I(TAG, "Certificate loaded"); - esp_http_client_config_t config = { + auto config = std::make_unique(esp_http_client_config_t { .url = url.c_str(), .auth_type = HTTP_AUTH_TYPE_NONE, .cert_pem = reinterpret_cast(certificate.get()), @@ -23,39 +30,30 @@ void download(const std::string& url, const std::string& certFilePath, const std .method = HTTP_METHOD_GET, .timeout_ms = 5000, .transport_type = HTTP_TRANSPORT_OVER_SSL - }; + }); - TT_LOG_I(TAG, "Request init"); - auto client = esp_http_client_init(&config); - if (client == nullptr) { - TT_LOG_E(TAG, "Failed to create client"); + auto client = std::make_unique(); + if (!client->init(std::move(config))) { + onError(); return -1; } - TT_LOG_I(TAG, "Request opening"); - if (esp_http_client_open(client, 0) != ESP_OK) { - TT_LOG_E(TAG, "Failed to open"); + if (!client->open()) { + onError(); return -1; } - TT_LOG_I(TAG, "Fetching headers"); - if (esp_http_client_fetch_headers(client) < 0) { - TT_LOG_E(TAG, "Failed to fetch headers"); - esp_http_client_close(client); - esp_http_client_cleanup(client); + if (!client->fetchHeaders()) { + onError(); return -1; } - auto status_code = esp_http_client_get_status_code(client); - if (status_code < 200 || status_code >= 300) { - TT_LOG_E(TAG, "Status code %d", status_code); - esp_http_client_close(client); - esp_http_client_cleanup(client); + if (!client->isStatusCodeOk()) { + onError(); return -1; } - auto bytes_left = esp_http_client_get_content_length(client); - TT_LOG_I(TAG, "Fetching %d bytes", bytes_left); + auto bytes_left = client->getContentLength(); auto lock = file::getLock(downloadFilePath)->asScopedLock(); lock.lock(); @@ -63,31 +61,24 @@ void download(const std::string& url, const std::string& certFilePath, const std auto* file_mode = file_exists ? "r+" : "w"; auto* file = fopen(downloadFilePath.c_str(), file_mode); + TT_LOG_I(TAG, "Writing %d bytes to %s", bytes_left, downloadFilePath.c_str()); char buffer[512]; while (bytes_left > 0) { - int data_read = esp_http_client_read(client, buffer, 512); + int data_read = client->read(buffer, 512); if (data_read <= 0) { - esp_http_client_close(client); - esp_http_client_cleanup(client); + onError(); return -1; } bytes_left -= data_read; if (fwrite(buffer, 1, data_read, file) != data_read) { TT_LOG_E(TAG, "Failed to write all bytes"); fclose(file); - esp_http_client_close(client); - esp_http_client_cleanup(client); + onError(); return -1; } } fclose(file); - - // esp_http_client_read(client); - TT_LOG_I(TAG, "Request closing"); - esp_http_client_close(client); - TT_LOG_I(TAG, "Request cleanup"); - esp_http_client_cleanup(client); - TT_LOG_I(TAG, "Request done"); + onSuccess(); return 0; }); }