You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

319 lines
11 KiB

// networksettingspage.cpp — Network configuration form (список listen-сокетов)
#include "networksettingspage.h"
#include "../transport/config_updater.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QLabel>
#include <QCheckBox>
#include <QLineEdit>
#include <QListWidget>
#include <QPushButton>
#include <QNetworkInterface>
#include <QFile>
#include <QTextStream>
static const QString AUTO_IP_LABEL = "Auto (0.0.0.0)";
NetworkSettingsPage::NetworkSettingsPage(QWidget* parent)
: QWidget(parent)
{
auto* layout = new QVBoxLayout(this);
layout->setSpacing(12);
layout->setContentsMargins(0, 0, 0, 0);
auto* title = new QLabel("Listen Sockets", this);
title->setStyleSheet("font-weight: bold; font-size: 13px;");
layout->addWidget(title);
m_autoSocketsCheck = new QCheckBox("Auto sockets (UDP+TCP from interfaces)", this);
layout->addWidget(m_autoSocketsCheck);
m_serverList = new QListWidget(this);
m_serverList->setMinimumHeight(110);
layout->addWidget(m_serverList);
auto* btnRow = new QHBoxLayout();
m_addBtn = new QPushButton("Add", this);
m_removeBtn = new QPushButton("Remove", this);
btnRow->addWidget(m_addBtn);
btnRow->addWidget(m_removeBtn);
btnRow->addStretch();
layout->addLayout(btnRow);
// --- форма правки выбранного сокета ---
auto* formLayout = new QGridLayout();
formLayout->addWidget(new QLabel("Name:", this), 0, 0);
m_nameEdit = new QLineEdit(this);
m_nameEdit->setMinimumWidth(180);
formLayout->addWidget(m_nameEdit, 0, 1);
formLayout->addWidget(new QLabel("IP Address:", this), 1, 0);
m_ipCombo = new QComboBox(this);
m_ipCombo->setEditable(true);
m_ipCombo->setMinimumWidth(180);
formLayout->addWidget(m_ipCombo, 1, 1);
formLayout->addWidget(new QLabel("Port:", this), 2, 0);
m_portSpin = new QSpinBox(this);
m_portSpin->setRange(1, 65535);
m_portSpin->setValue(1333);
formLayout->addWidget(m_portSpin, 2, 1);
formLayout->addWidget(new QLabel("Protocol:", this), 3, 0);
m_protoCombo = new QComboBox(this);
m_protoCombo->addItems({"UDP", "TCP"});
formLayout->addWidget(m_protoCombo, 3, 1);
formLayout->addWidget(new QLabel("Type:", this), 4, 0);
m_typeCombo = new QComboBox(this);
m_typeCombo->addItems({"public", "nat", "private", "local"});
formLayout->addWidget(m_typeCombo, 4, 1);
formLayout->addWidget(new QLabel("Interface:", this), 5, 0);
m_interfaceCombo = new QComboBox(this);
m_interfaceCombo->setMinimumWidth(180);
formLayout->addWidget(m_interfaceCombo, 5, 1);
layout->addLayout(formLayout);
auto* note = new QLabel("Changes take effect after restart.", this);
note->setStyleSheet("color: gray; font-size: 11px;");
layout->addWidget(note);
layout->addStretch();
populateInterfaces();
populateAddresses();
connect(m_autoSocketsCheck, &QCheckBox::toggled, this, &NetworkSettingsPage::onAutoSocketsToggled);
connect(m_addBtn, &QPushButton::clicked, this, &NetworkSettingsPage::onAddServer);
connect(m_removeBtn, &QPushButton::clicked, this, &NetworkSettingsPage::onRemoveServer);
connect(m_serverList, &QListWidget::currentRowChanged, this, [this](int) { onServerSelected(); });
connect(m_nameEdit, &QLineEdit::textChanged, this, [this](const QString&) { onFieldChanged(); });
connect(m_ipCombo, &QComboBox::editTextChanged, this, [this](const QString&) { onFieldChanged(); });
connect(m_portSpin, QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int) { onFieldChanged(); });
connect(m_protoCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int) { onFieldChanged(); });
connect(m_typeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int) { onFieldChanged(); });
connect(m_interfaceCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int) { onFieldChanged(); });
}
static void splitAddr(const QString& addr, QString& ip, int& port) {
int lastColon = addr.lastIndexOf(':');
if (lastColon > 0) {
ip = addr.left(lastColon);
port = addr.mid(lastColon + 1).toInt();
} else {
ip = addr;
port = 0;
}
}
void NetworkSettingsPage::populateInterfaces() {
m_interfaceCombo->addItem("Auto (any)");
for (const QNetworkInterface& iface : QNetworkInterface::allInterfaces()) {
if (iface.flags() & QNetworkInterface::IsLoopBack) continue;
if (!(iface.flags() & QNetworkInterface::IsUp)) continue;
m_interfaceCombo->addItem(iface.name());
}
}
void NetworkSettingsPage::populateAddresses() {
m_ipCombo->addItem(AUTO_IP_LABEL);
for (const QNetworkInterface& iface : QNetworkInterface::allInterfaces()) {
if (iface.flags() & QNetworkInterface::IsLoopBack) continue;
if (!(iface.flags() & QNetworkInterface::IsUp)) continue;
for (const QNetworkAddressEntry& entry : iface.addressEntries()) {
if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol)
m_ipCombo->addItem(entry.ip().toString());
}
}
}
void NetworkSettingsPage::applyAutoSocketsState() {
bool manual = !m_autoSocketsCheck->isChecked();
m_serverList->setEnabled(manual);
m_addBtn->setEnabled(manual);
m_removeBtn->setEnabled(manual);
m_nameEdit->setEnabled(manual);
m_ipCombo->setEnabled(manual);
m_portSpin->setEnabled(manual);
m_protoCombo->setEnabled(manual);
m_typeCombo->setEnabled(manual);
m_interfaceCombo->setEnabled(manual);
}
void NetworkSettingsPage::refreshServerList(int selectRow) {
m_updating = true;
m_serverList->clear();
for (const ConfigServer& s : m_servers) {
m_serverList->addItem(QString("%1 %2 (%3)").arg(s.name, s.addr, s.transport));
}
if (selectRow >= 0 && selectRow < m_serverList->count())
m_serverList->setCurrentRow(selectRow);
else if (m_serverList->count() > 0)
m_serverList->setCurrentRow(0);
m_updating = false;
}
void NetworkSettingsPage::loadFormFromSelected() {
int row = m_serverList->currentRow();
if (row < 0 || row >= m_servers.size()) return;
const ConfigServer& s = m_servers[row];
m_updating = true;
m_nameEdit->setText(s.name);
QString ip; int port = 0;
splitAddr(s.addr, ip, port);
if (ip == "0.0.0.0") ip = AUTO_IP_LABEL;
m_ipCombo->setCurrentText(ip);
m_portSpin->setValue(port > 0 ? port : 1333);
m_protoCombo->setCurrentIndex(s.transport == "tcp" ? 1 : 0);
int typeIdx = m_typeCombo->findText(s.type);
m_typeCombo->setCurrentIndex(typeIdx >= 0 ? typeIdx : 0);
int ifIdx = m_interfaceCombo->findText(s.netif);
m_interfaceCombo->setCurrentIndex(ifIdx >= 0 ? ifIdx : 0);
m_updating = false;
}
void NetworkSettingsPage::updateSelectedServerFromForm() {
int row = m_serverList->currentRow();
if (row < 0 || row >= m_servers.size()) return;
ConfigServer& s = m_servers[row];
s.name = m_nameEdit->text().trimmed();
QString ip = m_ipCombo->currentText().trimmed();
if (ip == AUTO_IP_LABEL) ip = "0.0.0.0";
s.addr = ip + ":" + QString::number(m_portSpin->value());
s.transport = (m_protoCombo->currentIndex() == 1) ? "tcp" : "udp";
s.type = m_typeCombo->currentText().trimmed();
QString iface = m_interfaceCombo->currentText();
s.netif = iface.startsWith("Auto") ? QString() : iface;
}
void NetworkSettingsPage::updateSelectedListItemText() {
int row = m_serverList->currentRow();
if (row < 0 || row >= m_servers.size()) return;
const ConfigServer& s = m_servers[row];
m_updating = true;
m_serverList->item(row)->setText(QString("%1 %2 (%3)").arg(s.name, s.addr, s.transport));
m_updating = false;
}
void NetworkSettingsPage::loadFromConfig(const QString& configPath) {
m_configPath = configPath;
m_servers.clear();
QFile f(configPath);
if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
QString section;
ConfigServer cur;
bool inServer = false;
QTextStream in(&f);
while (!in.atEnd()) {
QString line = in.readLine().trimmed();
if (line.startsWith('[') && line.endsWith(']')) {
if (inServer) m_servers.append(cur);
inServer = false;
section = line.mid(1, line.length() - 2);
if (section.startsWith("server:")) {
cur = ConfigServer();
cur.name = section.mid(7);
cur.transport = "udp";
cur.type = "public";
inServer = true;
}
continue;
}
if (!inServer || !line.contains('=')) continue;
QString key = line.section('=', 0, 0).trimmed();
QString val = line.section('=', 1).trimmed();
if (key == "addr") cur.addr = val;
else if (key == "transport") cur.transport = val;
else if (key == "type") cur.type = val;
else if (key == "netif") cur.netif = val;
}
if (inServer) m_servers.append(cur);
f.close();
}
/* auto_sockets из [global] */
bool autoSockets = false;
f.setFileName(configPath);
if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
QString section;
QTextStream in(&f);
while (!in.atEnd()) {
QString line = in.readLine().trimmed();
if (line.startsWith('[') && line.endsWith(']')) {
section = line.mid(1, line.length() - 2);
continue;
}
if ((section == "global" || section.isEmpty()) && line.startsWith("auto_sockets=")) {
QString v = line.section('=', 1).trimmed();
autoSockets = (v.compare("yes", Qt::CaseInsensitive) == 0 || v == "1");
break;
}
}
f.close();
}
m_autoSocketsCheck->setChecked(autoSockets);
refreshServerList();
applyAutoSocketsState();
}
void NetworkSettingsPage::saveToConfig(const QString& configPath) const {
/* 1. Серверные секции — полная перезапись */
config_rewrite_servers(configPath, m_servers);
/* 2. auto_sockets */
config_update_option(configPath, "global", "auto_sockets",
m_autoSocketsCheck->isChecked() ? "yes" : "no",
CONFIG_UPDATE_REPLACE);
}
void NetworkSettingsPage::onAutoSocketsToggled(bool /*on*/) {
applyAutoSocketsState();
}
void NetworkSettingsPage::onAddServer() {
int n = m_servers.size() + 1;
QString name;
for (;;) {
name = QString("srv%1").arg(n);
bool used = false;
for (const ConfigServer& s : m_servers) if (s.name == name) { used = true; break; }
if (!used) break;
n++;
}
ConfigServer s;
s.name = name;
s.addr = "0.0.0.0:1333";
s.transport = "udp";
s.type = "public";
m_servers.append(s);
refreshServerList(m_servers.size() - 1);
loadFormFromSelected();
}
void NetworkSettingsPage::onRemoveServer() {
int row = m_serverList->currentRow();
if (row < 0 || row >= m_servers.size()) return;
m_servers.removeAt(row);
refreshServerList(row);
loadFormFromSelected();
}
void NetworkSettingsPage::onServerSelected() {
loadFormFromSelected();
}
void NetworkSettingsPage::onFieldChanged() {
if (m_updating) return;
updateSelectedServerFromForm();
updateSelectedListItemText();
}