Browse Source

Add message identities and plan the remaining feedback work

master
evgeny 5 days ago
parent
commit
d40f58d79a
  1. 8
      doc/tasks.md
  2. 24
      lib/strbuf.c
  3. 3
      lib/strbuf.h
  4. 12
      src/chat/db_sync.c

8
doc/tasks.md

@ -13,6 +13,14 @@
канонические данные набора эмодзи и ответа, формат неизменяемого poll-сообщения
(single/multiple, allow_custom_answer), проверку и подсчёт результатов при получении
исходного сообщения; подключить headless, desktop и Android интерфейсы.
План продолжения:
1. Сохранить индексируемый message_id в msg_<channel>, вернуть его через API сообщений.
2. Добавить общий каталог эмодзи и канонические кодеки poll/answer/reactions;
single/multiple и allow_custom_answer проверяются ядром.
3. Добавить снимок результатов, список голосовавших и собственные состояния;
неизвестное сообщение откладывает учёт ответа, получение сообщения обновляет представление.
4. Подключить единый командный API к CLI, desktop и Android; команды выполняются в uasync.
5. Прогнать проверки кодеков и сетевые сценарии, собрать интерфейсы и выполнить check.sh.
[ ] **tcp_proxy_full: проверить аномальные значения elapsed в отчёте** — 06.10.2026:
`/tmp/utun3-check.log` при успешной передаче показывает длительности вроде

24
lib/strbuf.c

@ -3,6 +3,7 @@
*/
#include "strbuf.h"
#include "mem.h"
#include "debug_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -69,6 +70,29 @@ void strbuf_addc(struct strbuf *sb, char c) {
sb->buf[sb->len] = '\0';
}
/* Экранирует ASCII-управляющие байты; UTF-8 сохраняется без преобразования. */
int strbuf_add_json_string(struct strbuf* sb, const char* text) {
if (!sb || strbuf_addf(sb, "\"") < 0) goto failed;
const unsigned char* p = (const unsigned char*)(text ? text : "");
while (*p) {
int rc;
if (*p == '"' || *p == '\\') rc = strbuf_addf(sb, "\\%c", *p);
else if (*p < 32) rc = strbuf_addf(sb, "\\u%04x", *p);
else {
const unsigned char* start = p;
while (*p >= 32 && *p != '"' && *p != '\\') p++;
rc = strbuf_addf(sb, "%.*s", (int)(p - start), start);
if (rc < 0) goto failed;
continue;
}
if (rc < 0) goto failed;
p++;
}
if (strbuf_addf(sb, "\"") >= 0) return 0;
failed:
DEBUG_ERROR(DEBUG_CATEGORY_SYS, "strbuf: JSON string allocation failed"); return -1;
}
void strbuf_adds(struct strbuf *sb, const char *s) {
if (!s) return;
size_t slen = strlen(s);

3
lib/strbuf.h

@ -41,6 +41,9 @@ void strbuf_reset(struct strbuf *sb);
int strbuf_addf(struct strbuf *sb, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
/* Добавить JSON-строку с кавычками и полным экранированием; NULL означает пустую строку. 0/-1. */
int strbuf_add_json_string(struct strbuf* sb, const char* text);
void strbuf_addc(struct strbuf *sb, char c);
void strbuf_adds(struct strbuf *sb, const char *s);

12
src/chat/db_sync.c

@ -7,6 +7,7 @@
#include "../routing_layer/topo_group.h"
#include "../routing_layer/topo_node_sqlite.h"
#include "member_sync.h"
#include "chat_feedback.h"
#include "../transport_layer/etcp_dump.h"
#include "../transport_layer/secure_channel.h"
#include "../../lib/debug_config.h"
@ -562,6 +563,9 @@ static int db_record_insert(struct DB_SYNC_INSTANCE* si,
sqlite3_stmt* stmt;
int rc;
uint8_t message_id[32];
if (chat_message_id(si->group_id, ts, author_sig, message_id) < 0) return -1;
// Verify author signature (mandatory)
if (db_verify_author_sig(si, ts, author_node_id, json, jlen, author_sig) != 0) {
sqlite3_stmt* del;
@ -598,8 +602,8 @@ static int db_record_insert(struct DB_SYNC_INSTANCE* si,
if (si_prep(si, &stmt,
"INSERT INTO \"%s\""
" (timestamp,node_id,id,chain_hash,flags,data,"
" author_signature,local_attrs,delivered_peers,delivery_chain)"
" VALUES (?,?,?,?,0,?,?,?,0,'')") != SQLITE_OK)
" author_signature,local_attrs,delivered_peers,delivery_chain,message_id)"
" VALUES (?,?,?,?,0,?,?,?,0,'',?)") != SQLITE_OK)
{ DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "db_record_insert INSERT prep: %s", sqlite3_errmsg(db)); sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); return -1; }
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)ts);
sqlite3_bind_int64(stmt, 2, (sqlite3_int64)author_node_id);
@ -610,6 +614,7 @@ static int db_record_insert(struct DB_SYNC_INSTANCE* si,
sqlite3_bind_blob(stmt, 6, author_sig, DB_SIG_SIZE, SQLITE_STATIC);
if (local_attrs && local_attrs[0]) sqlite3_bind_text(stmt, 7, local_attrs, -1, SQLITE_STATIC);
else sqlite3_bind_text(stmt, 7, "", -1, SQLITE_STATIC);
sqlite3_bind_blob(stmt, 8, message_id, sizeof(message_id), SQLITE_STATIC);
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if (rc != SQLITE_DONE) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "INSERT: %s", sqlite3_errmsg(db)); sqlite3_exec(db, "ROLLBACK", NULL, NULL, NULL); return -1; }
@ -1707,7 +1712,7 @@ struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst, const
// Create table — PK is (timestamp, node_id), author_signature NOT NULL
{
char sql[512];
char sql[768];
snprintf(sql, sizeof(sql),
"CREATE TABLE IF NOT EXISTS \"%s\" ("
" timestamp INTEGER NOT NULL,"
@ -1717,6 +1722,7 @@ struct DB_SYNC_INSTANCE* db_sync_instance_add(struct UTUN_INSTANCE* inst, const
" flags INTEGER NOT NULL DEFAULT 0,"
" data BLOB,"
" author_signature BLOB NOT NULL,"
" message_id BLOB NOT NULL UNIQUE CHECK(length(message_id)=32),"
" local_attrs TEXT DEFAULT '',"
" delivered_peers INTEGER NOT NULL DEFAULT 0,"
" delivery_chain TEXT NOT NULL DEFAULT '',"

Loading…
Cancel
Save