Rdzleo aeae073e4f chore(git): 把 components/common/ 纳入 git 跟踪
components/common/ 是项目自己写的代码 (火山 RTC SDK 的 wrapper + HTTP 客户端 + JSON
工具 + 设备管理), 历史上被 .gitignore 的 components/ 规则误排除。共 15 个文件 2750
行项目代码长期未被 git 跟踪, 修改易丢失, 不利于多设备开发和回溯。

主要变动:

1. .gitignore
   - 改 components/ → /components/* (顶层 children 而非目录本身)
   - 加 !/components/common/ 例外, 让项目自己代码进入跟踪
   - 加 esp-spot/**/components/ 显式 ignore 子项目里的 components/ 保持原行为

2. components/common/ 首次入 git (~2750 行)
   - inc/volc_rtc.h, src/volc_rtc.c — 火山 RTC SDK 的封装层
   - inc/volc_http.h, src/volc_http.c — HTTP 客户端
   - inc/util/volc_json.h, src/volc_json.c — JSON 工具
   - inc/base/volc_device_manager.h, src/volc_device_manager.c — RTC 设备凭证管理
   - inc/util/volc_log.h — 日志宏
   - inc/util/volc_list.h — 链表工具
   - inc/volc_conv_ai.h — 会话 AI 接口定义
   - inc/volc_platform.h, src/volc_platform.c — 平台抽象
   - inc/base/volc_base.h — 基础类型

未跟踪的兄弟目录 (保持 ignore):
   - components/78__esp-opus-encoder/ (IDF managed component)
   - components/volc_engine_rtc_lite/ (火山 RTC SDK 二进制库)
   - components/zlib/ (第三方库)

后续 fix(rtc) NULL guard 等 components/common/ 的改动将作为独立 commit。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 13:50:52 +08:00

207 lines
7.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (2025) Beijing Volcano Engine Technology Ltd.
// SPDX-License-Identifier: Apache-2.0
#include "volc_http.h"
#include <string.h>
#include <esp_log.h>
#include <esp_http_client.h>
#include "volc_platform.h"
#include "esp_crt_bundle.h"
static const char* TAG = "VOLC_HTTP";
// Response data structure for event handler
typedef struct {
char* buffer;
size_t buffer_size;
size_t total_read;
size_t max_size;
} response_data_t;
// HTTP client event handler to capture response data
static esp_err_t http_event_handler(esp_http_client_event_t *evt)
{
response_data_t *response_data = (response_data_t *)evt->user_data;
switch (evt->event_id) {
case HTTP_EVENT_ON_DATA:
if (response_data && evt->data && evt->data_len > 0) {
// Calculate available space in buffer
size_t available = response_data->max_size - response_data->total_read;
if (available > 0) {
// Copy data to buffer (don't exceed max size)
size_t copy_len = (evt->data_len < available) ? evt->data_len : available;
memcpy(response_data->buffer + response_data->total_read, evt->data, copy_len);
response_data->total_read += copy_len;
ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA: read %d bytes, total: %d", evt->data_len, response_data->total_read);
}
}
break;
default:
break;
}
return ESP_OK;
}
char* volc_http_post(const char* uri, const char* post_data, int data_len)
{
char* response_buffer = NULL;
esp_http_client_handle_t client = NULL;
int response_status = 0;
esp_err_t err = ESP_OK;
int attempts = 0;
const int max_attempts = 3;
if (!uri || !post_data || data_len <= 0) {
ESP_LOGE(TAG, "Invalid parameters: uri=%p, post_data=%p, data_len=%d", uri, post_data, data_len);
return NULL;
}
ESP_LOGD(TAG, "HTTP POST: uri=%s, post_data=%s, data_len=%d", uri, post_data, data_len);
/* Perform HTTP request with retries */
while (attempts < max_attempts) {
ESP_LOGI(TAG, "HTTP POST attempt %d/%d", attempts + 1, max_attempts);
/* Allocate buffer for response */
const size_t max_response_size = 16384; // 增加缓冲区大小到16KB解决响应被截断的问题
char *buffer = (char*)hal_malloc(max_response_size + 1);
if (!buffer) {
ESP_LOGE(TAG, "Failed to allocate buffer for response reading");
goto cleanup_attempt;
}
memset(buffer, 0, max_response_size + 1);
/* Initialize response data structure */
response_data_t response_data = {
.buffer = buffer,
.buffer_size = max_response_size + 1,
.total_read = 0,
.max_size = max_response_size
};
/* Configure HTTP client with event handler */
esp_http_client_config_t config = {
.url = uri,
.timeout_ms = 15000,
.transport_type = HTTP_TRANSPORT_OVER_SSL,
.crt_bundle_attach = esp_crt_bundle_attach,
.skip_cert_common_name_check = true,
.method = HTTP_METHOD_POST,
.event_handler = http_event_handler,
.user_data = &response_data, // Pass response data to event handler
.disable_auto_redirect = false, // Enable redirects
.max_redirection_count = 3, // Allow up to 3 redirects
};
/* Initialize HTTP client */
client = esp_http_client_init(&config);
if (client == NULL) {
ESP_LOGE(TAG, "Failed to initialize HTTP client");
hal_free(buffer);
goto cleanup_attempt;
}
/* Set content type to application/json */
err = esp_http_client_set_header(client, "Content-Type", "application/json");
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to set Content-Type header: %s", esp_err_to_name(err));
goto cleanup_attempt;
}
/* Set POST data */
err = esp_http_client_set_post_field(client, post_data, data_len);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to set POST field: %s", esp_err_to_name(err));
goto cleanup_attempt;
}
/* Perform HTTP request */
/* The event handler will capture response data */
ESP_LOGI(TAG, "Performing HTTP request...");
err = esp_http_client_perform(client);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to perform HTTP request: %s", esp_err_to_name(err));
goto cleanup_attempt;
}
/* Get response status */
response_status = esp_http_client_get_status_code(client);
ESP_LOGI(TAG, "HTTP response status: %d", response_status);
if (response_status == 200) {
/* Get content length from response header */
int64_t content_length = esp_http_client_get_content_length(client);
ESP_LOGI(TAG, "Content-Length: %lld, actually read: %d", content_length, response_data.total_read);
if (response_data.total_read > 0) {
/* Ensure null termination */
buffer[response_data.total_read] = '\0';
ESP_LOGI(TAG, "Successfully read response: %d bytes", response_data.total_read);
ESP_LOGD(TAG, "Response data: %s", buffer);
/* Copy to final buffer */
response_buffer = (char*)hal_malloc(response_data.total_read + 1);
if (response_buffer) {
memcpy(response_buffer, buffer, response_data.total_read + 1);
} else {
ESP_LOGE(TAG, "Failed to allocate final response buffer");
}
} else {
ESP_LOGE(TAG, "Failed to read any response data via event handler");
/* Try a fallback method - read directly after perform */
ESP_LOGI(TAG, "Trying fallback: direct read after perform...");
int fallback_read = esp_http_client_read_response(client, buffer, max_response_size);
if (fallback_read > 0) {
ESP_LOGI(TAG, "Fallback successful: read %d bytes", fallback_read);
buffer[fallback_read] = '\0';
ESP_LOGD(TAG, "Response data: %s", buffer);
response_buffer = (char*)hal_malloc(fallback_read + 1);
if (response_buffer) {
memcpy(response_buffer, buffer, fallback_read + 1);
}
} else {
ESP_LOGE(TAG, "Fallback also failed: %d", fallback_read);
}
}
} else {
ESP_LOGW(TAG, "Non-200 status: %d", response_status);
}
cleanup_attempt:
/* Clean up client and buffer */
if (client != NULL) {
esp_http_client_cleanup(client);
client = NULL;
}
if (buffer != NULL) {
hal_free(buffer);
buffer = NULL;
}
/* If we got a response, break the retry loop */
if (response_buffer) {
break;
}
attempts++;
if (attempts < max_attempts) {
int backoff_ms = 500 * attempts;
ESP_LOGI(TAG, "Retrying in %d ms...", backoff_ms);
hal_thread_sleep(backoff_ms);
}
}
if (attempts == max_attempts) {
ESP_LOGE(TAG, "HTTP POST failed after %d attempts", max_attempts);
}
ESP_LOGI(TAG, "HTTP POST request completed, response_buffer=%p", response_buffer);
return response_buffer;
}