diff --git a/src/chat/chat_poll.c b/src/chat/chat_poll.c index 0135028e..cdee79f7 100644 --- a/src/chat/chat_poll.c +++ b/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. */