From fa296163b51b104b1d64cb4d13f4da48b3f28584 Mon Sep 17 00:00:00 2001 From: luozheng <1732036298@qq.com> Date: Wed, 24 Sep 2025 22:56:27 +0800 Subject: [PATCH] =?utf8?q?=E6=B7=BB=E5=8A=A0=E8=A1=A8=E6=83=85=E4=B8=8B?= =?utf8?q?=E8=BD=BD=E5=8D=8F=E8=AE=AE=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../sdk/zhihui/leiniao/imsl_ln/CMakeLists.txt | 1 + code/sdk/zhihui/leiniao/imsl_ln/ln_api.c | 162 +++++++-- code/sdk/zhihui/leiniao/imsl_ln/ln_api.h | 26 +- .../sdk/zhihui/leiniao/imsl_ln/ln_api_emoji.c | 314 ++++++++---------- 4 files changed, 286 insertions(+), 217 deletions(-) diff --git a/code/sdk/zhihui/leiniao/imsl_ln/CMakeLists.txt b/code/sdk/zhihui/leiniao/imsl_ln/CMakeLists.txt index 5ba40bc62..98f893cdd 100644 --- a/code/sdk/zhihui/leiniao/imsl_ln/CMakeLists.txt +++ b/code/sdk/zhihui/leiniao/imsl_ln/CMakeLists.txt @@ -19,6 +19,7 @@ set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ln_api_ota.c ${CMAKE_CURRENT_SOURCE_DIR}/ln_api_websocket.c ${CMAKE_CURRENT_SOURCE_DIR}/ln_api_schedule.c + ${CMAKE_CURRENT_SOURCE_DIR}/ln_api_emoji.c ) # 公共头文件路径(供其他模块引用) diff --git a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c index 188f3028a..23d9a95a3 100644 --- a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c +++ b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.c @@ -73,7 +73,7 @@ char *uapi_ln_get_device_version(void) if (!first_underline) { // 无下划线,直接使用原始版本号(异常情况处理) snprintf(g_device_version, sizeof(g_device_version), "%s", version_buf); - printf("g_device_version (no underline): %s\n", g_device_version); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"g_device_version (no underline): %s", g_device_version); return g_device_version; } @@ -82,7 +82,7 @@ char *uapi_ln_get_device_version(void) if (!second_underline) { // 只有一个下划线(如 "V1.0.0_20250920"),直接使用 snprintf(g_device_version, sizeof(g_device_version), "%s", version_buf); - printf("g_device_version (only one underline): %s\n", g_device_version); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"g_device_version (only one underline): %s", g_device_version); return g_device_version; } @@ -97,7 +97,7 @@ char *uapi_ln_get_device_version(void) strncpy(g_device_version, version_buf, target_len); g_device_version[target_len] = '\0'; // 手动添加字符串结束符 - printf("g_device_version: %s\n", g_device_version); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"g_device_version: %s", g_device_version); return g_device_version; } /* 获取设备token: 优先读本地缓存,判断过期,否则刷新 */ @@ -159,7 +159,7 @@ void uapi_ln_clear_device_token(void) { if(g_device_token != NULL) { - printf("clear device token\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"clear device token"); free(g_device_token); g_device_token = NULL; } @@ -198,6 +198,103 @@ void uapi_ln_set_device_bound(int val) { g_ln_is_device_bound = val; } +int uapi_ln_download_file(const char *url, const char *save_path) +{ + if (!url || !save_path) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] url or save_path is NULL"); + return ERRCODE_FAIL; + } + + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 开始下载: %s -> %s", url, save_path); + + HttpClient client = {0}; + HttpClientData client_data = {0}; + int ret = -1; + size_t total_written = 0; + // 打开文件准备写入 + FILE *fd = fopen(save_path, "wb+"); + if (!fd) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] fopen failed for %s", save_path); + return ERRCODE_FAIL; + } + + HTTPC_RESULT prep = ln_http_prepare_auto(&client_data, 2048, LN_CLIENT_PREPARE_SIZE * 2); + if (prep != HTTP_SUCCESS) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] prepare failed: %d", prep); + fclose(fd); + return ERRCODE_FAIL; + } + + // 建立连接 + ret = HttpClientConn(&client, url); + if (ret != 0) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] connection failed, ret=0x%x", ret); + fclose(fd); + HttpClientUnprepare(&client_data); + return ERRCODE_FAIL; + } + + // 发送GET请求 + ret = HttpClientSend(&client, url, HTTP_GET, &client_data); + if (ret != 0) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] send request failed, ret=0x%x", ret); + fclose(fd); + HttpClientClse(&client); + HttpClientUnprepare(&client_data); + return ERRCODE_FAIL; + } + + // 接收响应数据 + do + { + HTTPC_RESULT recv_res = HttpClientRecvResponse(&client, &client_data); + if (recv_res == HTTP_SUCCESS || recv_res == HTTP_EAGAIN) + { + if (client_data.contentBlockLen > 0) + { + size_t written = fwrite(client_data.responseBuf, 1, client_data.contentBlockLen, fd); + if (written != client_data.contentBlockLen) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] write failed, written=%zu, expected=%d", + written, client_data.contentBlockLen); + fclose(fd); + HttpClientClse(&client); + HttpClientUnprepare(&client_data); + return ERRCODE_FAIL; + } + total_written += written; + } + } + } while (client_data.isMore); + + if (client_data.responseContentLen == 0) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] receive length = 0"); + } + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] responsecode = %d", client.responseCode); + if (total_written == client_data.responseContentLen && client.responseCode == 200 && total_written > 0) + { + ret = ERRCODE_SUCC; + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] The file is downloaded successfully and the data is complete!"); + } + else + { + ret = ERRCODE_FAIL; + unlink(save_path); // 删除不完整文件 + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] The file data is incomplete!"); + } + + HttpClientUnprepare(&client_data); + HttpClientClse(&client); + fclose(fd); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] download process finished,ret=%d", ret); + return ret; +} /* 自适应申请HttpClient缓冲(保证header>=2048),失败则逐步扩容重试 */ HTTPC_RESULT ln_http_prepare_auto(HttpClientData *clientData, int header_size, int resp_size) @@ -281,7 +378,7 @@ static void ln_handle_ota_task_response(const char *json_buf, int json_len) { if (!json_buf || json_len <= 0) { - printf("[OTA] handle ota task: invalid json\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA] handle ota task: invalid json"); return; } char *text = (char *)malloc((size_t)json_len + 1); @@ -292,7 +389,7 @@ static void ln_handle_ota_task_response(const char *json_buf, int json_len) cJSON *root = cJSON_Parse(text); if (!root) { - printf("[OTA] handle ota task: json parse failed\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA] handle ota task: json parse failed"); free(text); return; } @@ -301,7 +398,7 @@ static void ln_handle_ota_task_response(const char *json_buf, int json_len) if (errorCode && cJSON_IsString(errorCode)) { /* 无升级或服务端错误 */ - printf("[OTA] task errorCode=%s\n", errorCode->valuestring); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA] task errorCode=%s", errorCode->valuestring); cJSON_Delete(root); free(text); return; @@ -310,7 +407,7 @@ static void ln_handle_ota_task_response(const char *json_buf, int json_len) cJSON *data = cJSON_GetObjectItem(root, "data"); if (!data || !cJSON_IsObject(data)) { - printf("[OTA] task data missing\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA] task data missing"); cJSON_Delete(root); free(text); return; @@ -323,7 +420,7 @@ static void ln_handle_ota_task_response(const char *json_buf, int json_len) cJSON *packageSize = cJSON_GetObjectItem(data, "packageSize"); if (!(targetVersion && cJSON_IsString(targetVersion) && updateType && (cJSON_IsNumber(updateType) || cJSON_IsString(updateType)))) { - printf("[OTA] task fields invalid\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA] task fields invalid"); cJSON_Delete(root); free(text); return; @@ -335,7 +432,7 @@ static void ln_handle_ota_task_response(const char *json_buf, int json_len) else if (cJSON_IsString(updateType)) ut = atoi(updateType->valuestring); g_ln_last_update_type = ut; - printf("[OTA] task parsed: targetVersion=%s updateType=%d url=%s md5=%s\n", + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA] task parsed: targetVersion=%s updateType=%d url=%s md5=%s", targetVersion->valuestring, ut, (packageUrl && cJSON_IsString(packageUrl)) ? packageUrl->valuestring : "", (packageMd5 && cJSON_IsString(packageMd5)) ? packageMd5->valuestring : ""); @@ -367,17 +464,17 @@ static void ln_handle_ota_task_response(const char *json_buf, int json_len) if (ut == 1) { /* 强制升级:直接触发下载 */ - printf("[OTA] force upgrade: trigger download(强制升级:直接触发下载)\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA] force upgrade: trigger download(强制升级:直接触发下载)"); push_ota_status(OTA_UI_STATUS_FORCE_START); } else if (ut == 0) { - printf("[OTA] optional upgrade: waiting for user confirmation(可选升级:等待用户确认)\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA] optional upgrade: waiting for user confirmation(可选升级:等待用户确认)"); push_ota_status(OTA_UI_STATUS_OPTIONAL_START); } else { - printf("[OTA] unknown updateType, skip\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA] unknown updateType, skip"); } cJSON_Delete(root); @@ -425,13 +522,13 @@ static int ln_ota_is_md5_ok(const char *file_path, const char *expected_md5) { if (file_path == NULL || expected_md5 == NULL || expected_md5[0] == '\0') { - printf("[OTA] md5 verify: invalid args\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA] md5 verify: invalid args"); return -1; } char calc[33] = {0}; if (ln_calc_file_md5_lower_hex(file_path, calc) != 0) { - printf("[OTA] md5 verify: calc failed for %s\n", file_path); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA] md5 verify: calc failed for %s", file_path); return -1; } /* 规范化期望md5为小写并截断为32字符 */ @@ -447,7 +544,7 @@ static int ln_ota_is_md5_ok(const char *file_path, const char *expected_md5) expect_lower[32] = '\0'; int ok = (strcmp(calc, expect_lower) == 0) ? 1 : 0; - printf("[OTA] md5 verify result=%s, calc=%s, expect=%s\n", ok ? "OK" : "FAIL", calc, expect_lower); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA] md5 verify result=%s, calc=%s, expect=%s", ok ? "OK" : "FAIL", calc, expect_lower); return ok; } @@ -458,37 +555,37 @@ static void handle_ota_download_msg(const OtaDownloadMsg *msg) if (!msg) return; switch (msg->status) { case OTA_DOWNLOAD_STATUS_PROGRESS: - printf("[OTA_DOWNLOAD] 下载进度: %d%%\n", msg->progress); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] 下载进度: %d%%", msg->progress); push_ota_progress(msg->progress); break; case OTA_DOWNLOAD_STATUS_COMPLETED: - printf("[OTA_DOWNLOAD] 下载完成,文件路径: %s\n", msg->file_path); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] 下载完成,文件路径: %s", msg->file_path); if (msg->file_path[0] && msg->md5[0]) { - printf("[OTA_DOWNLOAD] 开始MD5校验: %s\n", msg->md5); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] 开始MD5校验: %s", msg->md5); int md5_ok = ln_ota_is_md5_ok(msg->file_path, msg->md5); if (md5_ok == 1) { - printf("[OTA_DOWNLOAD] MD5校验成功,准备重启升级\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] MD5校验成功,准备重启升级"); push_ota_status(OTA_UI_STATUS_SUCCESS); /* 外部可在此触发升级动作 */ uaip_cmd_update_request(); } else if (md5_ok == 0) { - printf("[OTA_DOWNLOAD] MD5校验失败,建议重新下载\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] MD5校验失败,建议重新下载"); push_ota_status(OTA_UI_STATUS_FAILED); } else { - printf("[OTA_DOWNLOAD] MD5校验出错\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] MD5校验出错"); push_ota_status(OTA_UI_STATUS_FAILED); } } break; case OTA_DOWNLOAD_STATUS_FAILED: - printf("[OTA_DOWNLOAD] 下载失败: %s\n", msg->error_msg); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] 下载失败: %s", msg->error_msg); reset_cnt++; if(reset_cnt < 3){ do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_OTA_DOWNLOAD, NULL, 0); } break; default: - printf("[OTA_DOWNLOAD] 未知状态: %d\n", msg->status); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,"[OTA_DOWNLOAD] 未知状态: %d", msg->status); break; } } @@ -582,7 +679,7 @@ void ln_ws_process_message(const ws_data_msg_t *data_msg, ws_command_t type) printf("[WS] DownloadEmoji:下载表情\n"); if(json_str) { - // ln_parse_download_emoji(json_str, (int)strlen(json_str)); + ln_parse_download_emoji(json_str, (int)strlen(json_str)); } break; } @@ -590,7 +687,7 @@ void ln_ws_process_message(const ws_data_msg_t *data_msg, ws_command_t type) printf("[WS] DeleteEmoji:删除表情\n"); if(json_str) { - // ln_parse_delete_emoji(json_str, (int)strlen(json_str)); + ln_parse_delete_emoji(json_str, (int)strlen(json_str)); } break; } @@ -1215,6 +1312,19 @@ static void ln_http_server_send_task(void const *arg) { printf("LN_HTTP_SERVICE_CMD_AUDIO_RESUME:恢复播放\n"); } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_EMOJI_REPORT) + { + printf("LN_HTTP_SERVICE_CMD_EMOJI_REPORT:上报角色表情组下载状态\n"); + if(mail.data) + { + ln_emoji_report_status(mail.data); + } + } + else if (mail.cmd == LN_HTTP_SERVICE_CMD_EMOJI_REPORT_ALL) + { + printf("LN_HTTP_SERVICE_CMD_EMOJI_REPORT_ALL:上报所有角色表情组状态\n"); + // ln_emoji_report_all(mail.data); + } if (mail.data != NULL) { printf("free(mail.data)\n"); diff --git a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.h b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.h index c6bc20f59..2b541e880 100644 --- a/code/sdk/zhihui/leiniao/imsl_ln/ln_api.h +++ b/code/sdk/zhihui/leiniao/imsl_ln/ln_api.h @@ -59,6 +59,7 @@ typedef struct #define story_choose_file_path LN_DATA_PATH "/story/choose.txt" #define story_random_file_path LN_DATA_PATH "/story/random.txt" #define LN_CHARACTER_CONFIG_FILE LN_DATA_PATH "/character/character_config.json" +#define EMOJI_CACHE_BASE_PATH LN_DATA_PATH "/emoji/" // 表情缓存根目录 #define LN_CLIENT_PREPARE_SIZE 2 * 1024 #define TEST_MP3_DOWNLOAD 0 // 测试下载mp3 @@ -99,8 +100,8 @@ typedef struct #define LN_HTTP_SERVICE_CMD_AUDIO_RESUME 0x1006 /* 恢复播放 */ /* Emoji 上报结果接收命令 */ -#define LN_HTTP_RECV_EMOJI_REPORT 0x1007 -#define LN_HTTP_RECV_EMOJI_REPORT_ALL 0x1008 +#define LN_HTTP_SERVICE_CMD_EMOJI_REPORT 0x1007 /*上报角色表情组下载状态*/ +#define LN_HTTP_SERVICE_CMD_EMOJI_REPORT_ALL 0x1008 /*上报所有角色表情组状态*/ /* 故事-随机故事 请求体(可选主题)*/ typedef struct @@ -207,8 +208,8 @@ int uapi_ln_is_device_bound(void); void uapi_ln_set_device_bound(int val); /* 获取设备绑定用户ID */ const char *uapi_ln_get_user_id(void); -/* 获取设备角色配置 */ -LnCharacterConfig uapi_ln_get_character_config(void); +/*文件下载函数:从URL下载到指定路径*/ +int uapi_ln_download_file(const char *url, const char *save_path); /* ============================== 共享全局状态(跨文件) ============================== */ extern char *g_device_token; @@ -302,19 +303,12 @@ uint32_t ln_ota_get_task_http(const char *device_id, uint32_t ln_ota_download_flow_http(const char *device_id, const char *device_token, const char *source_version); +/* Emoji 表情上报接口 */ +/* 上报角色表情组下载状态 */ +void ln_emoji_report_status(char* status); +/* 上报所有角色表情组状态 */ +void ln_emoji_report_all(void); -/* Emoji 表情接口 */ -uint32_t ln_emoji_report_status_http(const char *device_id, - const char *device_token, - const char *character_id, - const char *eyes_color, - const char *eyes_shape, - const char *status); - -uint32_t ln_emoji_report_all_http(const char *device_id, - const char *device_token, - const LnEmojiGroup *groups, - int group_count); /* ============================== WebSocket 客户端接口 ============================== */ diff --git a/code/sdk/zhihui/leiniao/imsl_ln/ln_api_emoji.c b/code/sdk/zhihui/leiniao/imsl_ln/ln_api_emoji.c index 3c17f029a..36fa2b7cf 100644 --- a/code/sdk/zhihui/leiniao/imsl_ln/ln_api_emoji.c +++ b/code/sdk/zhihui/leiniao/imsl_ln/ln_api_emoji.c @@ -1,17 +1,16 @@ #include "ln_api.h" #include +#include #include #include "cJSON.h" #include #include #include #include +#include /* 宏定义 */ -#define EMOJI_CACHE_BASE_PATH "/emoji_cache/" // 表情缓存根目录 -#define EMOJI_DOWNLOAD_TASK_STACK 4096 // 下载任务栈大小 -#define EMOJI_DOWNLOAD_TASK_PRIO 25 // 下载任务优先级 -#define MAX_PATH_LEN 512 // 最大路径长度 +#define MAX_PATH_LEN 512 // 最大路径长度 /* 表情信息结构体定义 */ typedef struct @@ -59,49 +58,14 @@ static void ln_free_emoji_list() g_emoji_package.emojiCount = 0; } -/* 工具函数:创建多级目录 */ -static int ln_mkdir_p(const char *path) -{ - if (!path || *path == '\0') - return -1; - - char dir[MAX_PATH_LEN] = {0}; - strncpy(dir, path, sizeof(dir) - 1); - int len = strlen(dir); - if (dir[len - 1] != '/') - { - strncat(dir, "/", sizeof(dir) - 1 - len); - len++; - } - - char *p = dir + 1; - while (*p) - { - if (*p == '/') - { - *p = '\0'; - if (mkdir(dir, 0777) != 0 && errno != EEXIST) - { - return -1; - } - *p = '/'; - } - p++; - } - - // 创建最后一级目录 - if (mkdir(dir, 0777) != 0 && errno != EEXIST) - { - return -1; - } - return 0; -} - /* 工具函数:生成表情缓存路径 */ static void ln_gen_emoji_cache_path(const EmojiPackage *pkg, const EmotionEmoji *emoji, char *path, size_t path_len) { if (!pkg || !emoji || !path || path_len == 0) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 生成表情缓存路径失败,pkg=%p,emoji=%p,path=%p,path_len=%zu", pkg, emoji, path, path_len); return; + } // 路径格式:BASE/characterId/eyesColor_eyesShape/emotion.ext char ext[32] = {0}; @@ -110,15 +74,27 @@ static void ln_gen_emoji_cache_path(const EmojiPackage *pkg, const EmotionEmoji { strncpy(ext, dot, sizeof(ext) - 1); } + else + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 生成表情缓存路径失败,emojiUrl=%s", emoji->emojiUrl); + return; + } - snprintf(path, path_len, - "%s%s/%s_%s/%s%s", - EMOJI_CACHE_BASE_PATH, - pkg->characterId, - pkg->eyesColor, - pkg->eyesShape, - emoji->emotion, - ext); + // emojiUrl=https://ambybox-emoji.test.leiniao.com/v1/emoji/getEmoji?characterId=1&eyesColor=1&eyesShape=1&emotion=1 + // path=/user/userdata/leiniao/emoji/1/1_1/1.png + + // snprintf(path, path_len, + // "%s%s/%s_%s/%s%s", + // EMOJI_CACHE_BASE_PATH, + // pkg->characterId, + // pkg->eyesColor, + // pkg->eyesShape, + // emoji->emotion, + // ext); + // 暂时将文件存在EMOJI_CACHE_BASE_PATH下 + + snprintf(path, path_len, "%s%s%s", EMOJI_CACHE_BASE_PATH, emoji->emotion, ext); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 生成表情缓存路径成功,path=%s", path); } /* 工具函数:检查表情是否已缓存 */ @@ -130,75 +106,13 @@ static int ln_emoji_is_cached(const EmojiPackage *pkg, const EmotionEmoji *emoji return (stat(path, &st) == 0 && S_ISREG(st.st_mode)) ? 1 : 0; } -/* 文件下载函数:从URL下载到指定路径 */ -static int ln_download_file(const char *url, const char *save_path) -{ - if (!url || !save_path) - return -1; - - // 创建保存目录 - char dir[MAX_PATH_LEN] = {0}; - strncpy(dir, save_path, sizeof(dir) - 1); - char *last_slash = strrchr(dir, '/'); - if (last_slash) - { - *last_slash = '\0'; - if (ln_mkdir_p(dir) != 0) - { - printf("[DOWNLOAD] create dir %s failed\n", dir); - return -1; - } - } - - // 初始化HTTP客户端 - HttpClient client = {0}; - HttpClientData clientData = {0}; - HTTPC_RESULT prep = ln_http_prepare_auto(&clientData, 2048, 32 * 1024); // 增大接收缓冲区 - if (prep != HTTP_SUCCESS) - { - printf("[DOWNLOAD] prepare failed\n"); - return -1; - } - - // 发送GET请求 - HTTPC_RESULT res = HttpClientGetRequest(&client, url, &clientData); - if (res != HTTP_SUCCESS || HttpClientGetResponseCode(&client) != 200) - { - printf("[DOWNLOAD] GET %s failed\n", url); - HttpClientUnprepare(&clientData); - return -1; - } - - // 写入文件 - int fd = open(save_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd < 0) - { - printf("[DOWNLOAD] open %s failed\n", save_path); - HttpClientUnprepare(&clientData); - return -1; - } - - int write_len = write(fd, clientData.responseBuf, clientData.responseContentLen); - close(fd); - HttpClientUnprepare(&clientData); - - if (write_len != clientData.responseContentLen) - { - printf("[DOWNLOAD] write file failed\n"); - unlink(save_path); // 删除不完整文件 - return -1; - } - - printf("[DOWNLOAD] %s saved to %s\n", url, save_path); - return 0; -} - -/* 下载任务:批量下载表情并上报结果 */ -static void ln_emoji_download_task(void *arg) +/* 批量下载表情并上报结果 */ +static void ln_emoji_download(void *arg) { EmojiPackage *pkg = (EmojiPackage *)arg; if (!pkg || pkg->emojiCount <= 0 || !pkg->emojis) { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 没有表情需要下载"); g_emoji_downloading = 0; return; } @@ -211,34 +125,28 @@ static void ln_emoji_download_task(void *arg) // 跳过已缓存的文件 if (ln_emoji_is_cached(pkg, &pkg->emojis[i])) { - printf("[DOWNLOAD] emoji %s already cached\n", pkg->emojis[i].emotion); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] emoji %s already cached", pkg->emojis[i].emotion); continue; } // 下载并缓存 char save_path[MAX_PATH_LEN] = {0}; ln_gen_emoji_cache_path(pkg, &pkg->emojis[i], save_path, sizeof(save_path)); - if (ln_download_file(pkg->emojis[i].emojiUrl, save_path) != 0) + if (uapi_ln_download_file(pkg->emojis[i].emojiUrl, save_path) != ERRCODE_SUCC) { all_success = 0; - printf("[DOWNLOAD] emoji %s download failed\n", pkg->emojis[i].emotion); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] emoji %s download failed", pkg->emojis[i].emotion); } } + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "上报表情下载状态"); + // 下载完成后上报状态 const char *status = all_success ? "success" : "failed"; - uint32_t report_res = ln_emoji_report_status_http( - get_device_id(), // 假设存在设备ID获取接口 - get_device_token(), // 假设存在设备Token获取接口 - pkg->characterId, - pkg->eyesColor, - pkg->eyesShape, - status); - - printf("[DOWNLOAD] report status %s, result: %d\n", status, report_res); + do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_EMOJI_REPORT, (char *)status, strlen(status)); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] report status %s, all_success: %d", status, all_success); g_emoji_downloading = 0; - LOS_TaskDelete(NULL); // 删除当前任务(根据实际系统接口调整) } /* 启动下载任务 */ @@ -246,32 +154,20 @@ static void ln_start_emoji_download() { if (g_emoji_downloading) { - printf("[DOWNLOAD] already downloading, skip\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] already downloading, skip"); return; } if (g_emoji_package.emojiCount <= 0 || !g_emoji_package.emojis) { - printf("[DOWNLOAD] no emojis to download\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] no emojis to download"); return; } - g_emoji_downloading = 1; - - // 创建下载任务(基于LiteOS接口示例) - UINT32 task_id; - TSK_INIT_PARAM_S task_param = { - .pfnTaskEntry = (TSK_ENTRY_FUNC)ln_emoji_download_task, - .ulStackSize = EMOJI_DOWNLOAD_TASK_STACK, - .pcName = "emoji_download", - .usTaskPrio = EMOJI_DOWNLOAD_TASK_PRIO, - .pvArg = &g_emoji_package}; + // 下载表情 + ln_emoji_download(&g_emoji_package); - if (LOS_TaskCreate(&task_id, &task_param) != LOS_OK) - { - printf("[DOWNLOAD] create task failed\n"); - g_emoji_downloading = 0; - } + g_emoji_downloading = 1; } /* 解析下载表情命令JSON */ @@ -279,7 +175,7 @@ void ln_parse_download_emoji(const char *json_buf, int json_len) { if (!json_buf || json_len <= 0) { - printf("[DOWNLOAD_EMOJI] invalid json input\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_EMOJI] invalid json input"); return; } @@ -297,7 +193,7 @@ void ln_parse_download_emoji(const char *json_buf, int json_len) cJSON *root = cJSON_Parse(text); if (!root) { - printf("[DOWNLOAD_EMOJI] json parse failed\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_EMOJI] json parse failed"); free(text); return; } @@ -306,8 +202,8 @@ void ln_parse_download_emoji(const char *json_buf, int json_len) cJSON *errorCode = cJSON_GetObjectItem(root, "errorCode"); if (errorCode && !cJSON_IsNull(errorCode)) { - printf("[DOWNLOAD_EMOJI] server error: %s\n", - cJSON_IsString(errorCode) ? errorCode->valuestring : "unknown"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_EMOJI] server error: %s", + cJSON_IsString(errorCode) ? errorCode->valuestring : "unknown"); cJSON_Delete(root); free(text); return; @@ -317,7 +213,7 @@ void ln_parse_download_emoji(const char *json_buf, int json_len) cJSON *data = cJSON_GetObjectItem(root, "data"); if (!data || !cJSON_IsObject(data)) { - printf("[DOWNLOAD_EMOJI] no data object\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_EMOJI] no data object"); cJSON_Delete(root); free(text); return; @@ -351,7 +247,7 @@ void ln_parse_download_emoji(const char *json_buf, int json_len) g_emoji_package.emojis = (EmotionEmoji *)malloc(sizeof(EmotionEmoji) * count); if (!g_emoji_package.emojis) { - printf("[DOWNLOAD_EMOJI] malloc failed for emojis\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_EMOJI] malloc failed for emojis"); g_emoji_package.emojiCount = 0; } else @@ -379,18 +275,18 @@ void ln_parse_download_emoji(const char *json_buf, int json_len) } // 打印解析结果 - printf("[DOWNLOAD_EMOJI] parsed successfully:\n"); - printf(" characterId: %s\n", g_emoji_package.characterId); - printf(" eyesColor: %s\n", g_emoji_package.eyesColor); - printf(" eyesShape: %s\n", g_emoji_package.eyesShape); - printf(" emojiCount: %d\n", g_emoji_package.emojiCount); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_EMOJI] parsed successfully:"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " characterId: %s", g_emoji_package.characterId); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " eyesColor: %s", g_emoji_package.eyesColor); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " eyesShape: %s", g_emoji_package.eyesShape); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " emojiCount: %d", g_emoji_package.emojiCount); for (int i = 0; i < g_emoji_package.emojiCount; i++) { - printf(" emoji %d: emotion=%s, url=%s\n", - i + 1, - g_emoji_package.emojis[i].emotion, - g_emoji_package.emojis[i].emojiUrl); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " emoji %d: emotion=%s, url=%s", + i + 1, + g_emoji_package.emojis[i].emotion, + g_emoji_package.emojis[i].emojiUrl); } // 解析完成后启动下载任务 @@ -448,7 +344,7 @@ void ln_parse_delete_emoji(const char *json_buf, int json_len) { if (!json_buf || json_len <= 0) { - printf("[DELETE_EMOJI] invalid json input\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DELETE_EMOJI] invalid json input"); return; } @@ -463,7 +359,7 @@ void ln_parse_delete_emoji(const char *json_buf, int json_len) cJSON *root = cJSON_Parse(text); if (!root) { - printf("[DELETE_EMOJI] json parse failed\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DELETE_EMOJI] json parse failed"); free(text); return; } @@ -472,8 +368,8 @@ void ln_parse_delete_emoji(const char *json_buf, int json_len) cJSON *errorCode = cJSON_GetObjectItem(root, "errorCode"); if (errorCode && !cJSON_IsNull(errorCode)) { - printf("[DELETE_EMOJI] server error: %s\n", - cJSON_IsString(errorCode) ? errorCode->valuestring : "unknown"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DELETE_EMOJI] server error: %s", + cJSON_IsString(errorCode) ? errorCode->valuestring : "unknown"); cJSON_Delete(root); free(text); return; @@ -483,7 +379,7 @@ void ln_parse_delete_emoji(const char *json_buf, int json_len) cJSON *data = cJSON_GetObjectItem(root, "data"); if (!data || !cJSON_IsObject(data)) { - printf("[DELETE_EMOJI] no data object\n"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DELETE_EMOJI] no data object"); cJSON_Delete(root); free(text); return; @@ -508,10 +404,10 @@ void ln_parse_delete_emoji(const char *json_buf, int json_len) (eyesShape && cJSON_IsString(eyesShape)) ? eyesShape->valuestring : ""); // 打印解析结果 - printf("[DELETE_EMOJI] parsed successfully:\n"); - printf(" characterId: %s\n", del_characterId); - printf(" eyesColor: %s\n", del_eyesColor); - printf(" eyesShape: %s\n", del_eyesShape); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DELETE_EMOJI] parsed successfully:"); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " characterId: %s", del_characterId); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " eyesColor: %s", del_eyesColor); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " eyesShape: %s", del_eyesShape); // 删除本地表情缓存 char del_dir[MAX_PATH_LEN] = {0}; @@ -524,11 +420,11 @@ void ln_parse_delete_emoji(const char *json_buf, int json_len) if (ln_rmdir_recursive(del_dir) == 0) { - printf("[DELETE_EMOJI] cached files in %s deleted\n", del_dir); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DELETE_EMOJI] cached files in %s deleted", del_dir); } else { - printf("[DELETE_EMOJI] failed to delete cached files in %s\n", del_dir); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DELETE_EMOJI] failed to delete cached files in %s", del_dir); } // 清理资源 @@ -566,8 +462,13 @@ uint32_t ln_emoji_report_status_http(const char *device_id, const char *status) { if (!device_id || !device_token || !character_id || !eyes_color || !eyes_shape || !status) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] invalid input"); return ERRCODE_FAIL; + } + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] starting"); + // CAT1 保活 #ifdef SUPPORT_CAT1_SERVICE cat1_api_add_cat1_vote(); cat1_api_wakeup_cat1(1); @@ -580,12 +481,18 @@ uint32_t ln_emoji_report_status_http(const char *device_id, HttpClientData clientData = (HttpClientData){0}; if (ln_fill_auth_header(&client, device_id, device_token) != 0) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] fill auth header failed"); return ERRCODE_FAIL; + } /* 组装 JSON */ cJSON *root = cJSON_CreateObject(); if (!root) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] create root object failed"); return ERRCODE_FAIL; + } cJSON_AddStringToObject(root, "characterId", character_id); cJSON_AddStringToObject(root, "eyesColor", eyes_color); cJSON_AddStringToObject(root, "eyesShape", eyes_shape); @@ -593,36 +500,65 @@ uint32_t ln_emoji_report_status_http(const char *device_id, char *body = cJSON_PrintUnformatted(root); cJSON_Delete(root); if (!body) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] print unformatted failed"); return ERRCODE_FAIL; + } - HTTPC_RESULT prep = ln_http_prepare_auto(&clientData, 2048, 8 * 1024); + HTTPC_RESULT prep = ln_http_prepare_auto(&clientData, 2048, LN_CLIENT_PREPARE_SIZE / 2); if (prep != HTTP_SUCCESS) { free(body); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] prepare auto failed"); return ERRCODE_FAIL; } clientData.postBuf = body; clientData.postBufLen = (int)strlen(body); clientData.postContentType = (char *)"application/json"; + // 打印请求请求响应 + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] request body: %s", body); + // 使用说明: + // - 该接口用于设备向服务器同步表情下载/删除状态 + // - 设备执行表情下载或删除操作成功后,必须调用此接口 + // - 服务器会根据上报的信息更新小程序端的表情状态显示 + // - characterId、eyesColor、eyesShape三个字段组合标识一个唯一的表情组 + HTTPC_RESULT res = HttpClientPostRequest(&client, LN_EMOJI_REPORT_URL, &clientData); if (res != HTTP_SUCCESS) { free(body); HttpClientUnprepare(&clientData); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] request failed"); return ERRCODE_FAIL; } int code = HttpClientGetResponseCode(&client); if (clientData.responseBuf && clientData.responseBufLen > 0) { + // { + // "errorCode": null, + // "message": null, + // "data": "ok" + // } + // 打印成功响应 int real_len = clientData.responseContentLen > 0 ? clientData.responseContentLen : clientData.responseBufLen; - do_ln_http_server_recv_data(LN_HTTP_RECV_EMOJI_REPORT, clientData.responseBuf, (uint32_t)real_len); + char *response_buf = (char *)malloc(real_len + 1); + if (!response_buf) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] malloc failed for response_buf"); + return ERRCODE_FAIL; + } + memcpy(response_buf, clientData.responseBuf, real_len); + response_buf[real_len] = '\0'; + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] response body: %s", response_buf); + free(response_buf); } if (code != 200) { free(body); HttpClientUnprepare(&clientData); + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] response code not 200"); return ERRCODE_FAIL; } @@ -630,7 +566,6 @@ uint32_t ln_emoji_report_status_http(const char *device_id, HttpClientUnprepare(&clientData); return ERRCODE_SUCC; } - /* 7.2 上报设备所有表情组状态 */ uint32_t ln_emoji_report_all_http(const char *device_id, const char *device_token, @@ -707,7 +642,16 @@ uint32_t ln_emoji_report_all_http(const char *device_id, if (clientData.responseBuf && clientData.responseBufLen > 0) { int real_len = clientData.responseContentLen > 0 ? clientData.responseContentLen : clientData.responseBufLen; - do_ln_http_server_recv_data(LN_HTTP_RECV_EMOJI_REPORT_ALL, clientData.responseBuf, (uint32_t)real_len); + char *response_buf = (char *)malloc(real_len + 1); + if (!response_buf) + { + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] malloc failed for response_buf"); + return ERRCODE_FAIL; + } + memcpy(response_buf, clientData.responseBuf, real_len); + response_buf[real_len] = '\0'; + WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[EMOJI_REPORT_STATUS] response body: %s", response_buf); + free(response_buf); } if (code != 200) { @@ -719,4 +663,24 @@ uint32_t ln_emoji_report_all_http(const char *device_id, free(body); HttpClientUnprepare(&clientData); return ERRCODE_SUCC; +} + +/* 上报角色表情组下载状态 */ +void ln_emoji_report_status(char* status) +{ + ln_emoji_report_status_http(uapi_ln_get_device_id(), + uapi_ln_get_device_token(), + g_emoji_package.characterId, + g_emoji_package.eyesColor, + g_emoji_package.eyesShape, + status); +} + +/* 上报所有角色表情组状态 */ +void ln_emoji_report_all(void) +{ + ln_emoji_report_all_http(uapi_ln_get_device_id(), + uapi_ln_get_device_token(), + g_emoji_package.emojis, + g_emoji_package.emojiCount); } \ No newline at end of file -- 2.17.1