Create EspHttpClient

This commit is contained in:
Ken Van Hoeylandt 2025-10-23 23:59:15 +02:00
parent 99d053525c
commit a19c55d783
4 changed files with 145 additions and 38 deletions

View File

@ -0,0 +1,100 @@
#pragma once
#include <esp_http_client.h>
namespace tt::network {
class EspHttpClient {
static constexpr auto* TAG = "EspHttpClient";
std::unique_ptr<esp_http_client_config_t> 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<esp_http_client_config_t> 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;
}
};
}

View File

@ -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<void()> onSuccess,
std::function<void()> onError
);
}

View File

@ -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:

View File

@ -2,19 +2,26 @@
#include <Tactility/Tactility.h>
#include <Tactility/file/File.h>
#include <Tactility/network/Http.h>
#include <Tactility/network/EspHttpClient.h>
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<void()> onSuccess,
std::function<void()> 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<const char*>(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>(esp_http_client_config_t {
.url = url.c_str(),
.auth_type = HTTP_AUTH_TYPE_NONE,
.cert_pem = reinterpret_cast<const char*>(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<EspHttpClient>();
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;
});
}