#include "maze32_web.h" #include #include "esp_log.h" #define MAZE32_STATIC_CHUNK_SIZE 1024 static const char* TAG = "maze32_web"; static const char* INDEX_PATH = "/littlefs/index.html.gz"; static void preserve_static_context(void* context) { (void)context; } static esp_err_t send_index(httpd_req_t* request) { FILE* file = fopen(INDEX_PATH, "rb"); if (file == NULL) { ESP_LOGE(TAG, "Static asset is unavailable: %s", INDEX_PATH); httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "Приложение временно недоступно"); return ESP_FAIL; } httpd_resp_set_type(request, "text/html; charset=utf-8"); httpd_resp_set_hdr(request, "Content-Encoding", "gzip"); httpd_resp_set_hdr(request, "Cache-Control", "no-cache"); char buffer[MAZE32_STATIC_CHUNK_SIZE]; size_t bytes_read; esp_err_t result = ESP_OK; while ((bytes_read = fread(buffer, 1, sizeof(buffer), file)) > 0) { result = httpd_resp_send_chunk(request, buffer, bytes_read); if (result != ESP_OK) { break; } } if (ferror(file) != 0) { ESP_LOGE(TAG, "Failed while reading static asset: %s", INDEX_PATH); result = ESP_FAIL; } fclose(file); if (result == ESP_OK) { result = httpd_resp_send_chunk(request, NULL, 0); } return result; } static esp_err_t send_health(httpd_req_t* request) { const maze32_health_t* health = request->user_ctx; char response[192]; int length = snprintf(response, sizeof(response), "{\"status\":\"%s\",\"healthy\":%s,\"version\":\"%s\",\"errorCode\":%d}", maze32_health_state_name(health->state), maze32_health_is_healthy(health) ? "true" : "false", health->version, health->error_code); if (length < 0 || (size_t)length >= sizeof(response)) { httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "Диагностический ответ слишком большой"); return ESP_FAIL; } httpd_resp_set_type(request, "application/json"); httpd_resp_set_hdr(request, "Cache-Control", "no-store"); return httpd_resp_send(request, response, length); } esp_err_t maze32_web_start(httpd_handle_t* server, maze32_health_t* health, maze32_gateway_t* gateway) { if (server == NULL || health == NULL || gateway == NULL) { return ESP_ERR_INVALID_ARG; } httpd_config_t configuration = HTTPD_DEFAULT_CONFIG(); configuration.max_uri_handlers = 9; configuration.max_open_sockets = 9; configuration.lru_purge_enable = false; configuration.recv_wait_timeout = 5; configuration.send_wait_timeout = 1; configuration.global_user_ctx = gateway; configuration.global_user_ctx_free_fn = preserve_static_context; configuration.close_fn = maze32_gateway_close_socket; esp_err_t result = httpd_start(server, &configuration); if (result != ESP_OK) { return result; } const httpd_uri_t root = { .uri = "/", .method = HTTP_GET, .handler = send_index, .user_ctx = NULL, }; const httpd_uri_t index = { .uri = "/index.html", .method = HTTP_GET, .handler = send_index, .user_ctx = NULL, }; const httpd_uri_t health_uri = { .uri = "/health", .method = HTTP_GET, .handler = send_health, .user_ctx = health, }; result = httpd_register_uri_handler(*server, &root); if (result == ESP_OK) { result = httpd_register_uri_handler(*server, &index); } if (result == ESP_OK) { result = httpd_register_uri_handler(*server, &health_uri); } if (result != ESP_OK) { httpd_stop(*server); *server = NULL; return result; } ESP_LOGI(TAG, "HTTP server ready with static and health endpoints"); return ESP_OK; }