Browse Source

Log delayed answer validation and keep JSON percentages locale independent

master
evgeny 5 days ago
parent
commit
865e4cda59
  1. 28
      src/chat/chat_poll.c

28
src/chat/chat_poll.c

@ -159,9 +159,10 @@ int chat_feedback_snapshot(struct UTUN_INSTANCE* inst, const char* channel, cons
poll.mode == CHAT_POLL_SINGLE ? "single" : "multiple", poll.allow_custom_answer ? "true" : "false") < 0
|| strbuf_add_json_string(&out, poll.question) < 0 || strbuf_addf(&out, ",\"options\":[") < 0) goto done;
for (unsigned i = 0; i < poll.option_count; i++) {
unsigned percent = voters ? (unsigned)((10000ULL * votes[i] + voters / 2) / voters) : 0;
if (strbuf_addf(&out, "%s{\"id\":%u,\"text\":", i ? "," : "", i) < 0
|| strbuf_add_json_string(&out, poll.options[i]) < 0
|| strbuf_addf(&out, ",\"count\":%u,\"percent\":%.2f}", votes[i], voters ? 100.0 * votes[i] / voters : 0.0) < 0) goto done;
|| strbuf_addf(&out, ",\"count\":%u,\"percent\":%u.%02u}", votes[i], percent / 100, percent % 100) < 0) goto done;
}
if (strbuf_addf(&out, "],\"voters\":%u,\"custom_count\":%u,\"ver\":%llu,\"mine\":",
voters, custom_count, (unsigned long long)answer_ver) < 0
@ -179,10 +180,29 @@ done:
/* Сохраняем диагностику семантики при новом состоянии/получении исходного сообщения. */
void chat_feedback_check_message(struct UTUN_INSTANCE* inst, const char* channel, const uint8_t message_id[32]) {
char* snapshot = NULL;
if (chat_feedback_snapshot(inst, channel, message_id, &snapshot) == 0) {
DEBUG_DEBUG(DEBUG_CATEGORY_CHAT_SYNC, "poll: evaluated ch=%s state=%s", channel, snapshot); u_free(snapshot);
struct chat_poll poll; int is_poll, target = poll_target(inst, channel, message_id, &poll, &is_poll);
if (target < 0) return;
if (target) {
DEBUG_DEBUG(DEBUG_CATEGORY_CHAT_SYNC, "poll: evaluation deferred ch=%s; source message missing", channel); return;
}
char sql[256]; snprintf(sql, sizeof(sql),
"SELECT node_id,ver,data FROM feedback_%s WHERE message_id=? AND kind=2 AND length(data)>0", channel);
sqlite3_stmt* st = NULL;
if (sqlite3_prepare_v2(inst->topo_sqlite_db, sql, -1, &st, NULL) != SQLITE_OK) { poll_db_error(inst, "evaluate query"); return; }
sqlite3_bind_blob(st, 1, message_id, 32, SQLITE_STATIC); int step; unsigned accepted = 0, rejected = 0;
while ((step = sqlite3_step(st)) == SQLITE_ROW) {
struct chat_poll_answer answer;
if (chat_answer_decode(sqlite3_column_blob(st, 2), sqlite3_column_bytes(st, 2), &answer) < 0
|| !is_poll || !poll_answer_allowed(&poll, &answer)) {
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "poll: answer excluded ch=%s node=%016llx ver=%llu poll=%d mode=%u options=%u custom=%u",
channel, (unsigned long long)sqlite3_column_int64(st, 0), (unsigned long long)sqlite3_column_int64(st, 1),
is_poll, is_poll ? poll.mode : 0, is_poll ? poll.option_count : 0, is_poll ? poll.allow_custom_answer : 0);
rejected++;
} else accepted++;
}
sqlite3_finalize(st);
if (step != SQLITE_DONE) { poll_db_error(inst, "evaluate read"); return; }
if (accepted || rejected) DEBUG_DEBUG(DEBUG_CATEGORY_CHAT_SYNC, "poll: evaluated ch=%s valid=%u invalid=%u", channel, accepted, rejected);
}
/* Читает поле JSON с его типом. Отсутствующее поле имеет type=NULL. */

Loading…
Cancel
Save