|
|
|
|
@ -38,7 +38,7 @@ static const QSet<QString> CONTROL_KEYS = {
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static const QSet<QString> GUI_KEYS = { |
|
|
|
|
"db_path", "debug_file", "debug_level", "debug_categories", |
|
|
|
|
"db_path", "debug_file", "debug_level", |
|
|
|
|
"sound_dir", "sound_msg_incoming", "sound_msg_outgoing", |
|
|
|
|
"sound_connect", "sound_disconnect" |
|
|
|
|
}; |
|
|
|
|
@ -80,6 +80,35 @@ static const QStringList VALID_DEBUG_LEVELS = {
|
|
|
|
|
"none", "error", "warn", "info", "debug", "trace" |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Основные debug-категории для подсказки в секции [debug] (комментарием).
|
|
|
|
|
// Имена соответствуют lib/debug_config.c (g_debug_categories), уровень — разумный дефолт.
|
|
|
|
|
static const struct { const char* name; const char* level; } DEBUG_CATEGORY_HINTS[] = { |
|
|
|
|
{"sys", "error"}, |
|
|
|
|
{"connection", "info"}, |
|
|
|
|
{"etcp", "trace"}, |
|
|
|
|
{"crypto", "error"}, |
|
|
|
|
{"config", "info"}, |
|
|
|
|
{"tun", "error"}, |
|
|
|
|
{"routing", "info"}, |
|
|
|
|
{"timers", "error"}, |
|
|
|
|
{"bgp", "info"}, |
|
|
|
|
{"chat", "info"}, |
|
|
|
|
{"chat_sync", "info"}, |
|
|
|
|
{"member_sync", "info"}, |
|
|
|
|
{"socket", "error"}, |
|
|
|
|
{"control", "info"}, |
|
|
|
|
{"dump", "trace"}, |
|
|
|
|
{"traffic", "trace"}, |
|
|
|
|
{"debug", "trace"}, |
|
|
|
|
{"general", "info"}, |
|
|
|
|
{"nat", "info"}, |
|
|
|
|
{"keepalive", "error"}, |
|
|
|
|
{"media", "info"}, |
|
|
|
|
{"etcp_route", "info"}, |
|
|
|
|
{"etcp_dump", "trace"}, |
|
|
|
|
{"proxy", "info"}, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Sections: "" = global, use prefix match for dynamic sections
|
|
|
|
|
static bool isSectionValid(const QString& section) { |
|
|
|
|
if (section.isEmpty() || section == "global") return true; |
|
|
|
|
@ -305,7 +334,6 @@ bool NodeConfig::load() {
|
|
|
|
|
if (key == "db_path") m_dbPath = val; |
|
|
|
|
else if (key == "debug_file") m_debugFile = val; |
|
|
|
|
else if (key == "debug_level") m_debugLevel = val; |
|
|
|
|
else if (key == "debug_categories") m_debugCategories = val; |
|
|
|
|
} else if (debugSection) { |
|
|
|
|
if (!m_debugCategories.isEmpty()) m_debugCategories += ','; |
|
|
|
|
m_debugCategories += key + '=' + val; |
|
|
|
|
@ -357,18 +385,16 @@ bool NodeConfig::saveFull() {
|
|
|
|
|
out << "[gui]\n"; |
|
|
|
|
out << "db_path=" << (m_dbPath.isEmpty() ? "chat_data" : m_dbPath) << "\n"; |
|
|
|
|
out << "debug_file=" << m_debugFile << "\n"; |
|
|
|
|
out << "debug_level=" << (m_debugLevel.isEmpty() ? "info" : m_debugLevel) << "\n"; |
|
|
|
|
out << "debug_categories=" << m_debugCategories << "\n\n"; |
|
|
|
|
out << "debug_level=" << (m_debugLevel.isEmpty() ? "info" : m_debugLevel) << "\n\n"; |
|
|
|
|
|
|
|
|
|
if (!m_debugCategories.isEmpty()) { |
|
|
|
|
out << "[debug]\n"; |
|
|
|
|
QStringList dbg = m_debugCategories.split(',', Qt::SkipEmptyParts); |
|
|
|
|
for (const QString& d : dbg) { |
|
|
|
|
for (const auto& h : DEBUG_CATEGORY_HINTS) |
|
|
|
|
out << '#' << h.name << '=' << h.level << '\n'; |
|
|
|
|
for (const QString& d : m_debugCategories.split(',', Qt::SkipEmptyParts)) { |
|
|
|
|
int eq = d.indexOf('='); |
|
|
|
|
if (eq > 0) out << d.left(eq).trimmed() << '=' << d.mid(eq + 1).trimmed() << '\n'; |
|
|
|
|
} |
|
|
|
|
out << '\n'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
out << "[allowed_keys]\n"; |
|
|
|
|
out << "allow_all=yes\n\n"; |
|
|
|
|
@ -420,7 +446,6 @@ bool NodeConfig::save() {
|
|
|
|
|
config_update_in_lines(lines, "gui", "db_path", m_dbPath.isEmpty() ? "chat_data" : m_dbPath, true); |
|
|
|
|
config_update_in_lines(lines, "gui", "debug_file", m_debugFile, true); |
|
|
|
|
config_update_in_lines(lines, "gui", "debug_level", m_debugLevel.isEmpty() ? "info" : m_debugLevel, true); |
|
|
|
|
config_update_in_lines(lines, "gui", "debug_categories", m_debugCategories, true); |
|
|
|
|
|
|
|
|
|
/* [debug] section: each category=level as separate line */ |
|
|
|
|
QStringList dbg = m_debugCategories.split(',', Qt::SkipEmptyParts); |
|
|
|
|
|