From 3899e091d17fc7c322fd0e85dc76b800f82fe835 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 3 Nov 2026 12:48:38 +0100 Subject: [PATCH] Connect subgroup exit to DM closure and record sequence scope --- doc/dm_devgroup_plan.txt | 7 +++++-- src/chat/chat_devgroup.c | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/doc/dm_devgroup_plan.txt b/doc/dm_devgroup_plan.txt index 08185f926..82a527533 100644 --- a/doc/dm_devgroup_plan.txt +++ b/doc/dm_devgroup_plan.txt @@ -37,8 +37,11 @@ DEVICE адресуется только выбранным двум узлам. При превышении допустимого размера списка отправка отклоняется целиком: нельзя молча обрезать адресатов или показывать успешную полную доставку. -Ключ сообщения: (conv_id, author_node_id, seq). Счётчик устойчивый, отдельный -для автора в беседе. Время не определяет уникальность. Проверенные собственные +Ключ сообщения: (conv_id, author_node_id, seq). Устойчивый счётчик автора общий +для всех его бесед: это сохраняет уникальность mailbox (recipient,author,seq), +когда одна пара устройств одновременно переписывается в DEVICE и GROUPS. +История различает авторов независимо от UI-направления. Время не определяет +уникальность. Проверенные собственные реплики показываются исходящими, но не становятся новым источником рассылки. Повтор допускается только с тем же подписанным телом; конфликт отклоняется. Подпись охватывает стороны, снимок адресатов, содержимое и дескриптор вложения. diff --git a/src/chat/chat_devgroup.c b/src/chat/chat_devgroup.c index f4522c1db..2ec3c9df4 100644 --- a/src/chat/chat_devgroup.c +++ b/src/chat/chat_devgroup.c @@ -6,6 +6,7 @@ #include "../routing_layer/topo_node_sqlite.h" #include "../transport_layer/secure_channel.h" #include "../ntp_time.h" +#include "../dm/dm_core.h" #include "../../lib/mem.h" #include "../../lib/strbuf.h" #include @@ -56,7 +57,9 @@ static int cd_commit(struct UTUN_INSTANCE* inst, const struct devgroup_record* r DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "devgroup: invalid commit context/record"); return -1; } struct TOPO_NODE next = *current; next.devgroup = *r; next.ver = (current->ver % 255) + 1; + int leaving = current->devgroup.json[0] && !r->json[0]; if (cd_sql(db, "BEGIN IMMEDIATE")) return -1; + if (leaving && (dm_group_leave_prepare(inst, current->devgroup.ed) || dm_media_close_prepare(inst))) goto rollback; sqlite3_stmt* st = NULL; int rc; if (r->json[0]) { uint8_t wire[DEVGROUP_WIRE_MAX]; int n = devgroup_encode(r, wire, sizeof(wire)); @@ -84,6 +87,7 @@ static int cd_commit(struct UTUN_INSTANCE* inst, const struct devgroup_record* r } if (cd_sql(db, "COMMIT")) goto rollback; *current = next; + if (leaving) dm_media_close_committed(inst); DEBUG_INFO(DEBUG_CATEGORY_CHAT, "devgroup: committed node=%016llx member=%d timestamp=%llu", (unsigned long long)inst->node_id, !!r->json[0], (unsigned long long)next.timestamp); cd_publish(inst); return 0;