WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 开始下载: %s -> %s", url, save_path);
g_ln_is_file_downloading = 1;
- uapi_pm_add_sleep_veto(PM_ID_DEBUG);
HttpClient client = {0};
HttpClientData client_data = {0};
{
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] fopen failed for %s", save_path);
g_ln_is_file_downloading = 0;
- uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
return ERRCODE_FAIL;
}
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] prepare failed: %d", prep);
fclose(fd);
g_ln_is_file_downloading = 0;
- uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
return ERRCODE_FAIL;
}
fclose(fd);
HttpClientUnprepare(&client_data);
g_ln_is_file_downloading = 0;
- uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
return ERRCODE_FAIL;
}
HttpClientClse(&client);
HttpClientUnprepare(&client_data);
g_ln_is_file_downloading = 0;
- uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
return ERRCODE_FAIL;
}
fclose(fd);
HttpClientClse(&client);
HttpClientUnprepare(&client_data);
- uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
return ERRCODE_FAIL;
}
total_written += written;
{
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "删除不完整文件成功\r\n");
}
- uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
}
HttpClientUnprepare(&client_data);
fclose(fd);
g_ln_is_file_downloading = 0;
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 下载过程结束,ret=%d", ret);
- uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
return ret;
}
return ERRCODE_FAIL;
}
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD] 开始下载: %s -> %s", url, save_path);
+ uapi_pm_add_sleep_veto(PM_ID_DEBUG);
int ret = uapi_ln_download_file(url, save_path);
if (ERRCODE_SUCC != ret)
{
}
}
}
+ uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
return ret;
}
return ERRCODE_FAIL;
}
- if (g_ln_is_file_downloading == 1)
- {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_RESUME] 已有文件正在下载中");
- return ERRCODE_FAIL;
- }
- g_ln_is_file_downloading = 1;
-
long long resume_offset = 0;
/* 判断是否存在部分文件,计算续传偏移 */
{
int ret = -1;
size_t total_written = 0;
+ if(resume_offset > 0)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_RESUME] 断点续传,resume_offset=%lld", resume_offset);
+ }
+
/* 以追加模式打开(若服务端返回200将切换为覆盖写)*/
FILE *fd = fopen(save_path, resume_offset > 0 ? "ab+" : "wb+");
if (!fd)
{
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_RESUME] fopen failed for %s", save_path);
- g_ln_is_file_downloading = 0;
return ERRCODE_FAIL;
}
{
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_RESUME] prepare failed: %d", prep);
fclose(fd);
- g_ln_is_file_downloading = 0;
return ERRCODE_FAIL;
}
{
HttpClientUnprepare(&client_data);
fclose(fd);
- g_ln_is_file_downloading = 0;
return ERRCODE_FAIL;
}
int hdr = snprintf(header_buf, 128, "Range: bytes=%lld-\r\n", resume_offset);
free(header_buf);
HttpClientUnprepare(&client_data);
fclose(fd);
- g_ln_is_file_downloading = 0;
return ERRCODE_FAIL;
}
HttpClientSetCustomHeader(&client, header_buf);
if (header_buf) free(header_buf);
fclose(fd);
HttpClientUnprepare(&client_data);
- g_ln_is_file_downloading = 0;
return ERRCODE_FAIL;
}
fclose(fd);
HttpClientClse(&client);
HttpClientUnprepare(&client_data);
- g_ln_is_file_downloading = 0;
return ERRCODE_FAIL;
}
fclose(fd);
HttpClientClse(&client);
HttpClientUnprepare(&client_data);
- g_ln_is_file_downloading = 0;
return ERRCODE_FAIL;
}
if (header_buf) free(header_buf);
HttpClientClse(&client);
HttpClientUnprepare(&client_data);
- g_ln_is_file_downloading = 0;
return ERRCODE_FAIL;
}
resume_offset = 0;
fclose(fd);
HttpClientClse(&client);
HttpClientUnprepare(&client_data);
- g_ln_is_file_downloading = 0;
return ERRCODE_FAIL;
}
total_written += written;
fclose(fd);
HttpClientClse(&client);
HttpClientUnprepare(&client_data);
- g_ln_is_file_downloading = 0;
return ERRCODE_FAIL;
}
total_written += written;
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_RESUME] write first block success, written=%zu", total_written);
}
}
else
HttpClientUnprepare(&client_data);
HttpClientClse(&client);
fclose(fd);
+ return ret;
+}
+/* 断点续传下载函数封装:带重试,不做UI通知与资源释放 */
+int uapi_ln_download_file_resume_with_retry(const char *url, const char *save_path, int max_retries)
+{
+ if (url == NULL || save_path == NULL || (max_retries <= 0 || max_retries > 10 ))
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_RESUME_WITH_RETRY] 参数无效");
+ return ERRCODE_FAIL;
+ }
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_RESUME_WITH_RETRY] 开始下载: %s -> %s", url, save_path);
+ if (uapi_ln_is_file_downloading() == 1)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_RESUME] 已有文件正在下载中");
+ return ERRCODE_FAIL;
+ }
+ g_ln_is_file_downloading = 1;
+
+ //添加睡眠投票
+ uapi_pm_add_sleep_veto(PM_ID_DEBUG);
+
+ int ret = uapi_ln_download_file_resume(url, save_path);
+ if (ERRCODE_SUCC != ret)
+ {
+ for (int i = 1; i <= max_retries; i++)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_RESUME_WITH_RETRY] 重试 %d/%d", i, max_retries);
+ ret = uapi_ln_download_file_resume(url, save_path);
+ if (ERRCODE_SUCC == ret)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[DOWNLOAD_RESUME_WITH_RETRY] 重试成功 %d", i);
+ break;
+ }
+ }
+ }
g_ln_is_file_downloading = 0;
+ //移除睡眠投票
+ uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
return ret;
}
/* 自适应申请HttpClient缓冲(保证header>=2048),失败则逐步扩容重试 */
/* 表情信息结构体定义 */
typedef struct
{
- char *emotion; // 心情类型(动态分配)
- char *emojiUrl; // 表情文件URL(动态分配)
+ char *emotion; // 心情类型(动态分配)
+ char *emojiUrl; // 表情文件URL(动态分配)
+ long long size; // 表情文件大小(字节,支持断点续传判断;0 表示未知)
} EmotionEmoji;
/* 表情包配置结构体 */
continue;
}
- // 下载并缓存
+ // 下载并缓存(支持断点续传:当目标文件存在且小于应有大小时,从断点续传)
char save_path[MAX_PATH_LEN] = {0};
ln_gen_emoji_cache_path(pkg, &pkg->emojis[i], save_path, sizeof(save_path));
/* 确保保存目录存在 */
uapi_create_folder(dir_buf);
}
}
- if (uapi_ln_download_with_retry(pkg->emojis[i].emojiUrl, save_path, 3) != ERRCODE_SUCC)
+ if (uapi_ln_download_file_resume_with_retry(pkg->emojis[i].emojiUrl, save_path, 3) != ERRCODE_SUCC)
{
all_success = 0;
failed_count++;
{
cJSON *emotion = cJSON_GetObjectItem(item, "emotion");
cJSON *emojiUrl = cJSON_GetObjectItem(item, "emojiUrl");
+ cJSON *size_node = cJSON_GetObjectItem(item, "size");
g_emoji_package.emojis[i].emotion = ln_safe_strdup((emotion && cJSON_IsString(emotion)) ? emotion->valuestring : "");
g_emoji_package.emojis[i].emojiUrl = ln_safe_strdup((emojiUrl && cJSON_IsString(emojiUrl)) ? emojiUrl->valuestring : "");
+ /* 解析单个表情大小(字节) */
+ long long emoji_size = 0;
+ if (size_node)
+ {
+ if (cJSON_IsNumber(size_node))
+ {
+ emoji_size = (long long)size_node->valuedouble;
+ }
+ else if (cJSON_IsString(size_node) && size_node->valuestring)
+ {
+ emoji_size = atoll(size_node->valuestring);
+ }
+ }
+ g_emoji_package.emojis[i].size = (emoji_size > 0) ? emoji_size : 0;
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, " emoji %d: emotion=%s, url=%s, size=%lld",
+ i + 1,
+ g_emoji_package.emojis[i].emotion,
+ g_emoji_package.emojis[i].emojiUrl,
+ g_emoji_package.emojis[i].size);
}
}
}