Cancel unfinished DM files when the local subgroup is left

This commit is contained in:
evgeny committed 2026-11-03 12:48:20 +01:00
1 parent a587e8dfdd
commit a053d83a60
2 files changed
+34 -3

No files matched your search

+28 -3
View File
@@ -247,6 +247,27 @@ void dm_media_forget_committed(struct UTUN_INSTANCE* inst, const char* conv) {
dm_cleanup_pump(inst->dm_media);
}
int dm_media_close_prepare(struct UTUN_INSTANCE* inst) {
if (!inst->dm_media) return 0;
return dm_media_exec(inst, "UPDATE dm_local_files SET generation=0 WHERE conv_id IN"
" (SELECT conv_id FROM dm_conversations WHERE closed=1) AND NOT EXISTS"
" (SELECT 1 FROM dm_files f WHERE f.conv_id=dm_local_files.conv_id AND f.ready=1"
" AND (dm_local_files.path=f.local_path OR dm_local_files.path=substr(f.local_path,1,length(f.local_path)-5)||'.cipher'))");
}
void dm_media_close_committed(struct UTUN_INSTANCE* inst) {
struct dm_media_state* media = inst->dm_media;
if (!media) return;
for (struct dm_file_job* job = media->jobs, *next; job; job = next) {
next = job->next;
if (job->transfer && job->work == DM_FILE_RECEIVE && dm_conversation_access(inst, job->conv, NULL, NULL)) {
DEBUG_INFO(DEBUG_CATEGORY_DM, "DM files: cancel after group exit conv=%s", job->conv);
file_transfer_cancel(job->transfer);
}
}
dm_cleanup_pump(media);
}
/* Подписанная роль и живые мемберы в одной области; тип NAT не даёт полномочий. */
int dm_media_scope(struct UTUN_INSTANCE* inst, uint64_t group, uint64_t node,
const char* role, uint64_t author, uint64_t recipient) {
@@ -554,7 +575,8 @@ static void dm_file_done(void* arg, int error) {
}
int custody = job->work == DM_FILE_CUSTODY;
if (error || job->error || media->closing) goto fail;
if (!custody && !dm_history_current(inst, job->conv, job->generation)) {
if (!custody && (!dm_history_current(inst, job->conv, job->generation) ||
dm_conversation_access(inst, job->conv, NULL, NULL))) {
DEBUG_INFO(DEBUG_CATEGORY_DM, "DM files: discard deleted preparation conv=%s generation=%llu work=%d", job->conv,
(unsigned long long)job->generation, job->work); goto fail;
}
@@ -734,7 +756,9 @@ int dm_send_file(struct UTUN_INSTANCE* inst, const char* conv, const char* path,
job->media = media; job->work = DM_FILE_PREPARE; job->author = inst->node_id;
job->generation = dm_history_generation(inst, conv);
job->request_id = request_id;
if (!dm_history_current(inst, conv, job->generation)) { u_free(job); return -1; }
if (!dm_history_current(inst, conv, job->generation) || dm_conversation_access(inst, conv, NULL, NULL)) {
u_free(job); return -1;
}
snprintf(job->conv, sizeof(job->conv), "%s", conv); job->info = *info; job->remove_source = remove_source;
snprintf(job->input, sizeof(job->input), "%s", path);
sqlite3_stmt* st = dm_media_prepare(inst, "SELECT peer_x25519 FROM dm_conversations WHERE conv_id=?");
@@ -1076,7 +1100,8 @@ static void dm_files_tick(struct dm_media_state* media, uint64_t now) {
struct UTUN_INSTANCE* inst = media->inst;
for (int i = 0; i < 8; i++) {
sqlite3_stmt* st = dm_media_prepare(inst, "SELECT id,dir,author,recipient,group_id,body,ready,holder,expires,receipt"
" FROM dm_files WHERE retry_at<=? ORDER BY retry_at,seq LIMIT 1");
" FROM dm_files WHERE retry_at<=? AND conv_id IN"
" (SELECT conv_id FROM dm_conversations WHERE closed=0) ORDER BY retry_at,seq LIMIT 1");
if (!st) return;
sqlite3_bind_int64(st, 1, (sqlite3_int64)now);
int rc = sqlite3_step(st);
+6
View File
@@ -97,6 +97,12 @@ int dm_media_forget_prepare(struct UTUN_INSTANCE* inst, const char* conv, uint64
/* Только после commit: отменить transfer удалённых UUID и начать асинхронную уборку старых поколений.
* Callback отмены transfer синхронен; ожидания workers здесь нет, busy защищает их пути. */
void dm_media_forget_committed(struct UTUN_INSTANCE* inst, const char* conv);
/* В транзакции выхода пометить незавершённые файлы closed-бесед для durable уборки.
* Готовые plaintext/ciphertext остаются. 0/-1, без media — пустая операция. */
int dm_media_close_prepare(struct UTUN_INSTANCE* inst);
/* После commit выхода отменить передачи closed-бесед. Workers завершатся с отказом
* публикации в историю; уборка ждёт их holds. Готовые локальные вложения сохраняются. */
void dm_media_close_committed(struct UTUN_INSTANCE* inst);
/* Зарегистрировать принадлежащий приложению path и увеличить busy до запуска worker/transfer.
* conv/generation должны быть текущими и видимыми; 0=захват, -1=ошибка/чужое поколение пути. */
int dm_media_file_hold(struct UTUN_INSTANCE* inst, const char* conv, uint64_t generation, const char* path);