From 75124e0efa20017d37bd2c769d81136a7732b85d Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 27 Oct 2026 01:48:13 +0100 Subject: [PATCH] Preserve independent NAT details in desktop diagnostics --- tools/chatgui/src/addressprofiletext.h | 12 ++++++-- tools/chatgui/src/debug_ui.h | 6 ++-- tools/chatgui/src/gui_language.h | 6 +++- tools/chatgui/tests/test_gui_language.cpp | 37 +++++++++++++++++++++++ 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/tools/chatgui/src/addressprofiletext.h b/tools/chatgui/src/addressprofiletext.h index 225a2f7e..1d0ae3a1 100644 --- a/tools/chatgui/src/addressprofiletext.h +++ b/tools/chatgui/src/addressprofiletext.h @@ -1,18 +1,24 @@ +/* Представление профиля endpoint в GUI: mapping, доступность входа и источник измерения. + * Использовать для полей enum из address_profile.h; происхождение самого адреса (interface/NAT) + * не подменяет измерение. Функция форматирует строку, не выполняет сетевых проверок. */ #pragma once #include #include #include "../../../src/routing_layer/address_profile.h" -// Показывает результат измерения отдельно от происхождения адреса (интерфейс или NAT). +/* mapping/inbound/source — enum address_mapping/address_inbound/address_profile_source. + * Возвращает QString с переводом текущего ChatGui; при source=NONE — NAT not determined. + * Известный inbound сохраняется при любом mapping; STUN помечается отдельно. UNKNOWN mapping → NAT?, + * EIM с неизвестным inbound → EIM?. Допустимость полей проверяет вызывающий. */ inline QString addressProfileText(int mapping, int inbound, int source) { if (source == ADDRESS_SOURCE_NONE) return QCoreApplication::translate("ChatGui", "NAT not determined"); QString text; switch (mapping) { case ADDRESS_MAP_UNCHANGED: text = QCoreApplication::translate("ChatGui", "No NAT"); break; case ADDRESS_MAP_EIM: text = inbound == ADDRESS_IN_UNKNOWN ? "EIM?" : "EIM"; break; - case ADDRESS_MAP_DEPENDENT: return "DEPENDENT"; - default: return "NAT?"; + case ADDRESS_MAP_DEPENDENT: text = "DEPENDENT"; break; + default: text = "NAT?"; break; } if (inbound == ADDRESS_IN_OPEN) text += QCoreApplication::translate("ChatGui", "; inbound open"); else if (inbound == ADDRESS_IN_CONTACT) text += QCoreApplication::translate("ChatGui", "; inbound filtered"); diff --git a/tools/chatgui/src/debug_ui.h b/tools/chatgui/src/debug_ui.h index ae0a0a6c..a1e44f09 100644 --- a/tools/chatgui/src/debug_ui.h +++ b/tools/chatgui/src/debug_ui.h @@ -1,8 +1,10 @@ -/* Макросы логирования GUI через общий debug_config, категория GENERAL. */ +/* Макросы GUI_ERROR/WARN/INFO/DEBUG: printf-формат и аргументы в общий logger, категория general. + * Уровень, файл и фильтры задаются debug_config; используются стандартные DEBUG_* с контекстом вызова. + * Аргументы форматирования не вычисляются, если уровень отфильтрован. Файл не содержит своего состояния. */ #pragma once extern "C" { -#include "../../lib/debug_config.h" +#include "../../../lib/debug_config.h" } #define GUI_ERROR(fmt, ...) DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, fmt, ##__VA_ARGS__) diff --git a/tools/chatgui/src/gui_language.h b/tools/chatgui/src/gui_language.h index 2fff8c5a..d2b17dd9 100644 --- a/tools/chatgui/src/gui_language.h +++ b/tools/chatgui/src/gui_language.h @@ -1,10 +1,14 @@ -/* Выбор языка интерфейса независимо от регионального формата дат и чисел. */ +/* Выбор поддерживаемого языка интерфейса независимо от формата дат и чисел QLocale. + * Не устанавливает QTranslator и не меняет системную locale: возвращает код en/ru. */ #pragma once #include #include #include +/* preference=en/ru выбирает язык явно; прочие значения (включая system) используют systemLanguages. + * По умолчанию берётся QLocale::system().uiLanguages(). Проверка идёт по порядку списка, + * без учёта регистра/региона (- и _); первый поддерживаемый язык побеждает, иначе возвращается en. */ inline QString resolveGuiLanguage(const QString& preference, const QStringList& systemLanguages = QLocale::system().uiLanguages()) { if (preference == QStringLiteral("en") || preference == QStringLiteral("ru")) return preference; for (const QString& language : systemLanguages) { diff --git a/tools/chatgui/tests/test_gui_language.cpp b/tools/chatgui/tests/test_gui_language.cpp index f35212c1..9e7fe9e0 100644 --- a/tools/chatgui/tests/test_gui_language.cpp +++ b/tools/chatgui/tests/test_gui_language.cpp @@ -1,4 +1,5 @@ #include "../src/gui_language.h" +#include "../src/addressprofiletext.h" #include "../src/networksettingspage.h" #include "../transport/node_config.h" #include "../transport/config_updater.h" @@ -67,6 +68,42 @@ private slots: QCOMPARE(resolveGuiLanguage("en", {"ru-RU"}), QString("en")); } + void addressProfilesKeepIndependentFields_data() { + QTest::addColumn("mapping"); QTest::addColumn("inbound"); QTest::addColumn("source"); + QTest::addColumn("expected"); + QTest::newRow("unmeasured") << int(ADDRESS_MAP_UNKNOWN) << int(ADDRESS_IN_UNKNOWN) << int(ADDRESS_SOURCE_NONE) + << QStringLiteral("NAT not determined"); + QTest::newRow("unchanged-untested") << int(ADDRESS_MAP_UNCHANGED) << int(ADDRESS_IN_UNKNOWN) << int(ADDRESS_SOURCE_ETCP) + << QStringLiteral("No NAT; inbound untested"); + QTest::newRow("unchanged-open") << int(ADDRESS_MAP_UNCHANGED) << int(ADDRESS_IN_OPEN) << int(ADDRESS_SOURCE_ETCP) + << QStringLiteral("No NAT; inbound open"); + QTest::newRow("unchanged-filtered-stun") << int(ADDRESS_MAP_UNCHANGED) << int(ADDRESS_IN_CONTACT) << int(ADDRESS_SOURCE_STUN) + << QStringLiteral("No NAT; inbound filtered (STUN)"); + QTest::newRow("eim-untested-stun") << int(ADDRESS_MAP_EIM) << int(ADDRESS_IN_UNKNOWN) << int(ADDRESS_SOURCE_STUN) + << QStringLiteral("EIM? (STUN)"); + QTest::newRow("eim-open") << int(ADDRESS_MAP_EIM) << int(ADDRESS_IN_OPEN) << int(ADDRESS_SOURCE_ETCP) + << QStringLiteral("EIM; inbound open"); + QTest::newRow("eim-filtered") << int(ADDRESS_MAP_EIM) << int(ADDRESS_IN_CONTACT) << int(ADDRESS_SOURCE_ETCP) + << QStringLiteral("EIM; inbound filtered"); + QTest::newRow("dependent-untested") << int(ADDRESS_MAP_DEPENDENT) << int(ADDRESS_IN_UNKNOWN) << int(ADDRESS_SOURCE_ETCP) + << QStringLiteral("DEPENDENT"); + QTest::newRow("dependent-open") << int(ADDRESS_MAP_DEPENDENT) << int(ADDRESS_IN_OPEN) << int(ADDRESS_SOURCE_ETCP) + << QStringLiteral("DEPENDENT; inbound open"); + QTest::newRow("dependent-filtered-stun") << int(ADDRESS_MAP_DEPENDENT) << int(ADDRESS_IN_CONTACT) << int(ADDRESS_SOURCE_STUN) + << QStringLiteral("DEPENDENT; inbound filtered (STUN)"); + QTest::newRow("unknown-open-stun") << int(ADDRESS_MAP_UNKNOWN) << int(ADDRESS_IN_OPEN) << int(ADDRESS_SOURCE_STUN) + << QStringLiteral("NAT?; inbound open (STUN)"); + QTest::newRow("unknown-filtered") << int(ADDRESS_MAP_UNKNOWN) << int(ADDRESS_IN_CONTACT) << int(ADDRESS_SOURCE_ETCP) + << QStringLiteral("NAT?; inbound filtered"); + } + + void addressProfilesKeepIndependentFields() { + QFETCH(int, mapping); QFETCH(int, inbound); QFETCH(int, source); QFETCH(QString, expected); + const address_profile profile = {uint8_t(mapping), uint8_t(inbound), uint8_t(source)}; + QVERIFY(address_profile_valid(&profile)); + QCOMPARE(addressProfileText(mapping, inbound, source), expected); + } + void autoSocketProtocols() { QTemporaryDir directory; QVERIFY(directory.isValid());