Cancel unfinished DM files when the local subgroup is left
This commit is contained in:
1 parent
a587e8dfdd
commit
a053d83a60
2 files changed
+34
-3
No files matched your search
+28
-3
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user