Reuse the database media base when restarting chat

This commit is contained in:
evgeny committed 2026-10-22 15:03:41 +02:00
1 parent 6b54b63986
commit 3bb8f76b7d
2 files changed
+44 -4

No files matched your search

+10 -1
View File
@@ -178,7 +178,16 @@ int chat_core_init(struct UTUN_INSTANCE* inst, const char* db_path) {
const char* ls = strrchr(db_path, '/');
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; }
sqlite3_stmt* stored = NULL;
int rc = sqlite3_prepare_v2(cc->db, "SELECT value FROM ui_state WHERE key='media_base'", -1, &stored, NULL);
if (rc == SQLITE_OK) rc = sqlite3_step(stored);
int base_error = rc == SQLITE_ROW ? media_index_get_base(cc->db, mbase)
: rc == SQLITE_DONE ? media_index_set_base(cc->db, mbase) : -1;
int finish = stored ? sqlite3_finalize(stored) : SQLITE_OK;
if (base_error || finish != SQLITE_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "chat media_base initialization failed rc=%d: %s", rc, sqlite3_errmsg(cc->db));
chat_core_destroy(inst); return -1;
}
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "%s: media_base=%s", CC_ID, mbase);
}
+34 -3
View File
@@ -3,6 +3,7 @@
#include "../lib/file_io.h"
#include "../lib/debug_config.h"
#include "../src/media_delivery/media_index.h"
#include "../src/media_delivery/media_download.h"
#include "../src/media_async/media_async.h"
#include "../src/utun_instance.h"
#include "../src/chat/chat_core.h"
@@ -170,6 +171,7 @@ static void long_path(void) {
static int deleted_events, failed_submissions, successful_submissions;
static char delete_from_event[64];
static void download_done(void* arg, int error) { assert(error); (*(int*)arg)++; }
static void event(struct UTUN_INSTANCE* inst, int type, const uint8_t* data, int length) {
if (type == CHAT_EVT_CHANNEL_DELETED) deleted_events++;
if (type == CHAT_EVT_MSG_SUBMITTED) {
@@ -187,11 +189,25 @@ static void pending_deletion(void) {
char config[1024]; snprintf(config, sizeof(config), "[global]\ndb_path=%s\n[chatserver]\ngroup_autoconnect=0\nstorage_autoload=0\n", root);
struct UASYNC* ua = uasync_create(); assert(ua);
struct UTUN_INSTANCE* inst = utun_instance_create_from_str(ua, config); assert(inst);
assert(!utun_core_start(inst) && !chat_service_start(inst)); chat_event_set_handler(inst, event);
assert(!utun_core_start(inst));
struct denied denied = {.index = "idx_media_files_block_id"};
assert(!sqlite3_set_authorizer(inst->topo_sqlite_db, authorizer, &denied));
assert(chat_service_start(inst) == -1 && !inst->chat_started && !inst->chat_core);
assert(!sqlite3_set_authorizer(inst->topo_sqlite_db, NULL, NULL));
assert(!chat_service_start(inst)); chat_event_set_handler(inst, event);
chat_core_create_channel_auto(inst, "pending");
sqlite3_stmt* st = NULL; sqlite3* db = inst->topo_sqlite_db;
assert(!sqlite3_prepare_v2(db, "SELECT channel_id FROM channels WHERE name='pending'", -1, &st, NULL));
assert(!sqlite3_prepare_v2(db, "SELECT channel_id,owner_node_id,x25519_pubkey,x25519_privkey,ed25519_pubkey,"
"ed25519_privkey,signature FROM channels WHERE name='pending'", -1, &st, NULL));
assert(sqlite3_step(st) == SQLITE_ROW); char channel[64]; snprintf(channel, sizeof(channel), "%s", sqlite3_column_text(st, 0));
struct chat_channel_create recreate = {.inst = inst};
snprintf(recreate.channel_id, sizeof(recreate.channel_id), "%s", channel);
snprintf(recreate.name, sizeof(recreate.name), "pending"); recreate.owner_node_id = (uint64_t)sqlite3_column_int64(st, 1);
uint8_t* keys[] = {recreate.x25519_pubkey, recreate.x25519_privkey, recreate.ed25519_pubkey, recreate.ed25519_privkey, recreate.signature};
for (int i = 0; i < 5; i++) {
int size = i == 4 ? 64 : 32; assert(sqlite3_column_bytes(st, i + 2) == size);
memcpy(keys[i], sqlite3_column_blob(st, i + 2), size);
}
sqlite3_finalize(st);
char source[MEDIA_PATH_MAX], destinations[2][MEDIA_PATH_MAX];
assert(!media_index_path(root, "source", source)); write_file(source);
@@ -214,7 +230,8 @@ static void pending_deletion(void) {
assert(!scalar(db, "SELECT count(*) FROM channels WHERE name='pending'"));
assert(!scalar(db, "SELECT count(*) FROM media_files") && !scalar(db, "SELECT count(*) FROM media_preparations"));
assert(ma_file_size(source) == 14 && ma_file_size(destinations[0]) == -1 && ma_file_size(destinations[1]) == -1);
chat_core_ensure_channel_ready(inst, channel); uasync_poll(ua, 0);
chat_core_create_channel(inst, &recreate); uasync_poll(ua, 0);
assert(scalar(db, "SELECT count(*) FROM channels WHERE name='pending'") == 1 && si_find(inst, channel));
assert(!scalar(db, "SELECT count(*) FROM media_files"));
/* Обработчик MSG_SUBMITTED синхронный: удаление должно увидеть ещё живую задачу. */
@@ -228,6 +245,20 @@ static void pending_deletion(void) {
assert(deleted_events == 2 && successful_submissions == 1 && failed_submissions == 3 && !CC(inst)->media_submissions);
assert(!scalar(db, "SELECT count(*) FROM channels WHERE name='reentrant'"));
assert(ma_file_size(destinations[1]) == -1 && ma_file_size(source) == 14);
/* Отказ/синхронное завершение/дубликат имеют разные правила владения аргументом. */
uint8_t signatures[128] = {0}; struct media_index_result download = result; download.block_sigs = signatures;
int completed = 0;
assert(!media_download_start(inst, 0, &download, destinations[0], root, 0, download_done, &completed, NULL, NULL));
assert(completed == 1); /* Нет суперузлов: completion уже вызван, dl освобождён. */
assert(!media_index_delete_channel(db, "0", root));
completed = 0;
assert(!media_download_start(inst, 0, &download, destinations[0], root, inst->node_id ^ 0x55,
download_done, &completed, NULL, NULL));
assert(!completed);
assert(media_download_start(inst, 0, &download, destinations[0], root, 0, download_done, &completed, NULL, NULL) == -1);
assert(!completed && !media_download_cancel(inst, download.media_id, NULL, 0) && completed == 1);
assert(!media_index_delete_channel(db, "0", root));
utun_instance_destroy(inst); uasync_destroy(ua, 0);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "media regression pending deletion/two completions/recreation PASS");
}