diff --git a/src/chat/chat_core.c b/src/chat/chat_core.c index 31d97b86..1dc1ed59 100644 --- a/src/chat/chat_core.c +++ b/src/chat/chat_core.c @@ -107,6 +107,11 @@ int chat_core_init(struct UTUN_INSTANCE* inst, const char* db_path) { if (!cc->shared_db) sqlite3_close(cc->db); inst->chat_core = NULL; u_free(cc); return -1; } + if (strlen(db_path) >= sizeof(cc->db_path) || media_index_init(cc->db)) { + DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "chat media schema/path initialization failed"); + if (!cc->shared_db) sqlite3_close(cc->db); + inst->chat_core = NULL; u_free(cc); return -1; + } cc->inst = inst; cc->my_node_id = inst->node_id; @@ -141,9 +146,6 @@ int chat_core_init(struct UTUN_INSTANCE* inst, const char* db_path) { /* register adm_tags change callback → CHAT_EVT_MEMBER_UPDATED */ chat_member_init(inst); - /* create media_files table */ - media_index_init(cc->db); - db_exec(cc, "CREATE TABLE IF NOT EXISTS local_identity (" " id INTEGER PRIMARY KEY CHECK (id = 1)," @@ -172,13 +174,11 @@ int chat_core_init(struct UTUN_INSTANCE* inst, const char* db_path) { ); /* store media_base for block_req handler */ { - char mbase[512]; + char mbase[MEDIA_BASE_MAX]; const char* ls = strrchr(db_path, '/'); - if (ls) snprintf(mbase, sizeof(mbase), "%.*s", (int)(ls - db_path), db_path); - else snprintf(mbase, sizeof(mbase), "%s", db_path); - char sql[1024]; snprintf(sql, sizeof(sql), - "INSERT OR REPLACE INTO ui_state(key,value) VALUES('media_base','%s')", mbase); - sqlite3_exec(cc->db, sql, NULL, NULL, NULL); + if (ls) snprintf(mbase, sizeof(mbase), "%.*s", ls == db_path ? 1 : (int)(ls - db_path), db_path); + else snprintf(mbase, sizeof(mbase), "."); + if (media_index_set_base(cc->db, mbase)) { chat_core_destroy(inst); return -1; } DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: media_base=%s", CC_ID, mbase); } diff --git a/src/media_delivery/media_download.c b/src/media_delivery/media_download.c index df0896a0..857a3d72 100644 --- a/src/media_delivery/media_download.c +++ b/src/media_delivery/media_download.c @@ -639,30 +639,19 @@ void media_download_handle_chunk(struct UTUN_INSTANCE* inst, /* Регистрирует скачанные блоки в media_files (location = собранный файл), чтобы узел * мог отдавать их как держатель. Вызывается после успешной сборки и проверки хеша. */ -static void md_dl_register_servable(struct media_download* dl) { +static int md_dl_register_servable(struct media_download* dl) { struct UTUN_INSTANCE* inst = dl->inst; sqlite3* db = inst ? inst->topo_sqlite_db : NULL; - if (!db) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "%s: register_servable — no DB", MDL_ID); return; } - - char chat_id[32]; - snprintf(chat_id, sizeof(chat_id), "%llu", (unsigned long long)dl->group_id); - - /* location = dest_path относительно media_base (как в media_index_commit) */ - const char* rel = dl->dest_path; - size_t base_len = strlen(dl->media_base); - if (strncmp(rel, dl->media_base, base_len) == 0 && rel[base_len] == '/') - rel += base_len + 1; - - for (int n = 0; n < dl->num_blocks; n++) { - if (media_index_register_downloaded(db, dl->media_id, dl->blocks[n].block_id, - dl->content_hash, chat_id, rel, inst->node_id, - dl->file_size, dl->blocks[n].expected_size, n, - (int64_t)n * dl->block_size) != 0) { - DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "%s: register_servable failed blk=%d", MDL_ID, n); - } - } - DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "%s: registered %d downloaded blocks as servable (%s)", - MDL_ID, dl->num_blocks, rel); + if (!db) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "%s: register_servable without DB", MDL_ID); return -1; } + char chat_id[32]; snprintf(chat_id, sizeof(chat_id), "%llu", (unsigned long long)dl->group_id); + uint8_t* ids = u_malloc((uint32_t)dl->num_blocks * 16); + if (!ids) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "%s: register_servable allocation failed", MDL_ID); return -1; } + for (int n = 0; n < dl->num_blocks; n++) memcpy(ids + (size_t)n * 16, dl->blocks[n].block_id, 16); + struct media_index_result result = { .file_size = dl->file_size, .block_size = dl->block_size, + .num_blocks = dl->num_blocks, .block_ids = ids }; + memcpy(result.media_id, dl->media_id, 16); memcpy(result.content_hash, dl->content_hash, 32); + int rc = media_index_register_downloaded_file(db, &result, inst->node_id, chat_id, dl->dest_path, dl->media_base); + u_free(ids); return rc; } void media_download_handle_done(struct UTUN_INSTANCE* inst, @@ -783,8 +772,8 @@ void media_download_handle_done(struct UTUN_INSTANCE* inst, } } dl->assembled = 1; DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "%s: file assembled: %s", MDL_ID, dl->dest_path); - md_dl_register_servable(dl); - md_dl_finish(dl, 0); + int registered = md_dl_register_servable(dl); + md_dl_finish(dl, registered); return; } @@ -877,6 +866,15 @@ int media_download_start(struct UTUN_INSTANCE* inst, uint64_t group_id, struct media_delivery_ctx* md = &inst->md; if (!md->initialized) { DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "%s: start before media_delivery init", MDL_ID); return -1; } + char location[MEDIA_PATH_MAX]; + if (result->file_size <= 0 || result->block_size <= 0 || result->block_size > UINT32_MAX + || result->num_blocks <= 0 || (uint64_t)result->num_blocks > UINT32_MAX / 64 + || (result->file_size - 1) / result->block_size + 1 != result->num_blocks + || !result->block_ids || !result->block_sigs || media_index_location(dest_path, media_base, location) + || media_index_set_base(inst->topo_sqlite_db, media_base)) { + DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "%s: invalid file geometry/path/base before download", MDL_ID); return -1; + } + /* дедуп: та же медиа уже качается */ if (md_dl_find(inst, result->media_id)) { DEBUG_WARN(DEBUG_CATEGORY_GENERAL, "%s: DUPLICATE download media=%02x%02x... ignored", MDL_ID, result->media_id[0], result->media_id[1]); @@ -933,15 +931,6 @@ int media_download_start(struct UTUN_INSTANCE* inst, uint64_t group_id, dl = (struct media_download*)qe->data; - /* сохраняем media_base в ui_state — чтобы после скачивания узел мог отдавать блоки - (md_handle_block_req открывает файл по ui_state.media_base + location) */ - { - sqlite3_exec(inst->topo_sqlite_db, "CREATE TABLE IF NOT EXISTS ui_state(key TEXT PRIMARY KEY, value TEXT)", NULL, NULL, NULL); - sqlite3_stmt* us = NULL; - sqlite3_prepare_v2(inst->topo_sqlite_db, "INSERT OR REPLACE INTO ui_state(key,value) VALUES('media_base',?)", -1, &us, NULL); - if (us) { sqlite3_bind_text(us, 1, media_base, -1, SQLITE_STATIC); sqlite3_step(us); sqlite3_finalize(us); } - } - md_dl_collect_supernodes(inst, dl); dl->last_activity_tb = get_time_tb(); dl->watchdog_timer = uasync_set_timeout(inst->ua, (int)md_dl_stall_tb(inst), dl, md_dl_watchdog_cb, "md_dl_wd");