dns ui: compact tab + benchmark dialog and api endpoint
This commit is contained in:
@@ -36,6 +36,7 @@ from PySide6.QtWidgets import (
|
||||
|
||||
from api_client import ApiClient, DnsUpstreams
|
||||
from dashboard_controller import DashboardController, TraceMode
|
||||
from dns_benchmark_dialog import DNSBenchmarkDialog
|
||||
from traffic_mode_dialog import TrafficModeDialog
|
||||
|
||||
_NEXT_CHECK_RE = re.compile(r"(?i)next check in \d+s")
|
||||
@@ -420,31 +421,27 @@ RU: Агрессивный режим дополнительно дергает
|
||||
tip.setStyleSheet("color: gray;")
|
||||
main_layout.addWidget(tip)
|
||||
|
||||
ups_group = QGroupBox("Upstreams (auto-save)")
|
||||
ups_group.setToolTip("""EN: DNS upstreams for direct resolver mode (and non-wildcard lists in hybrid mode).
|
||||
RU: DNS апстримы для direct-резолвера (и для не-wildcard списков в hybrid режиме).""")
|
||||
ups_form = QFormLayout(ups_group)
|
||||
self.ent_def1 = QLineEdit()
|
||||
self.ent_def1.setToolTip("""EN: Upstream default1. You can set an IP (port 53 is assumed).
|
||||
RU: Апстрим default1. Можно указать IP (порт 53 по умолчанию).""")
|
||||
self.ent_def2 = QLineEdit()
|
||||
self.ent_def2.setToolTip("""EN: Upstream default2. You can set an IP (port 53 is assumed).
|
||||
RU: Апстрим default2. Можно указать IP (порт 53 по умолчанию).""")
|
||||
self.ent_meta1 = QLineEdit()
|
||||
self.ent_meta1.setToolTip("""EN: Upstream meta1. You can set an IP (port 53 is assumed).
|
||||
RU: Апстрим meta1. Можно указать IP (порт 53 по умолчанию).""")
|
||||
self.ent_meta2 = QLineEdit()
|
||||
self.ent_meta2.setToolTip("""EN: Upstream meta2. You can set an IP (port 53 is assumed).
|
||||
RU: Апстрим meta2. Можно указать IP (порт 53 по умолчанию).""")
|
||||
self.ent_def1.textEdited.connect(self._schedule_dns_autosave)
|
||||
self.ent_def2.textEdited.connect(self._schedule_dns_autosave)
|
||||
self.ent_meta1.textEdited.connect(self._schedule_dns_autosave)
|
||||
self.ent_meta2.textEdited.connect(self._schedule_dns_autosave)
|
||||
ups_form.addRow("default1", self.ent_def1)
|
||||
ups_form.addRow("default2", self.ent_def2)
|
||||
ups_form.addRow("meta1", self.ent_meta1)
|
||||
ups_form.addRow("meta2", self.ent_meta2)
|
||||
main_layout.addWidget(ups_group)
|
||||
resolver_group = QGroupBox("Resolver DNS")
|
||||
resolver_group.setToolTip("""EN: Compact resolver DNS status. Open benchmark to test/apply upstreams.
|
||||
RU: Компактный статус DNS резолвера. Открой benchmark для проверки/применения апстримов.""")
|
||||
resolver_layout = QVBoxLayout(resolver_group)
|
||||
|
||||
row = QHBoxLayout()
|
||||
self.btn_dns_benchmark = QPushButton("Open DNS benchmark")
|
||||
self.btn_dns_benchmark.clicked.connect(self.on_open_dns_benchmark)
|
||||
row.addWidget(self.btn_dns_benchmark)
|
||||
row.addStretch(1)
|
||||
resolver_layout.addLayout(row)
|
||||
|
||||
self.lbl_dns_resolver_upstreams = QLabel("Resolver upstreams: default[—, —] meta[—, —]")
|
||||
self.lbl_dns_resolver_upstreams.setStyleSheet("color: gray;")
|
||||
resolver_layout.addWidget(self.lbl_dns_resolver_upstreams)
|
||||
|
||||
self.lbl_dns_resolver_health = QLabel("Resolver health: —")
|
||||
self.lbl_dns_resolver_health.setStyleSheet("color: gray;")
|
||||
resolver_layout.addWidget(self.lbl_dns_resolver_health)
|
||||
|
||||
main_layout.addWidget(resolver_group)
|
||||
|
||||
smart_group = QGroupBox("SmartDNS")
|
||||
smart_group.setToolTip("""EN: SmartDNS is used for wildcard domains in hybrid mode.
|
||||
@@ -732,17 +729,58 @@ RU: Источник wildcard IP: резолвер, runtime nftset SmartDNS, и
|
||||
self.lbl_dns_mode_state.setText(txt)
|
||||
self.lbl_dns_mode_state.setStyleSheet(f"color: {color};")
|
||||
|
||||
def _set_dns_resolver_summary(self, ups: DnsUpstreams) -> None:
|
||||
d1 = (ups.default1 or "—").strip() or "—"
|
||||
d2 = (ups.default2 or "—").strip() or "—"
|
||||
m1 = (ups.meta1 or "—").strip() or "—"
|
||||
m2 = (ups.meta2 or "—").strip() or "—"
|
||||
self.lbl_dns_resolver_upstreams.setText(
|
||||
f"Resolver upstreams: default[{d1}, {d2}] meta[{m1}, {m2}]"
|
||||
)
|
||||
self.lbl_dns_resolver_upstreams.setStyleSheet("color: gray;")
|
||||
|
||||
avg_ms = self._ui_settings.value("dns_benchmark/last_avg_ms", None)
|
||||
ok = self._ui_settings.value("dns_benchmark/last_ok", None)
|
||||
fail = self._ui_settings.value("dns_benchmark/last_fail", None)
|
||||
timeout = self._ui_settings.value("dns_benchmark/last_timeout", None)
|
||||
if avg_ms is None or ok is None or fail is None:
|
||||
self.lbl_dns_resolver_health.setText("Resolver health: no benchmark yet")
|
||||
self.lbl_dns_resolver_health.setStyleSheet("color: gray;")
|
||||
return
|
||||
try:
|
||||
avg = int(avg_ms)
|
||||
ok_i = int(ok)
|
||||
fail_i = int(fail)
|
||||
timeout_i = int(timeout or 0)
|
||||
except Exception:
|
||||
self.lbl_dns_resolver_health.setText("Resolver health: no benchmark yet")
|
||||
self.lbl_dns_resolver_health.setStyleSheet("color: gray;")
|
||||
return
|
||||
color = "green" if avg < 200 else ("#b58900" if avg <= 400 else "red")
|
||||
if timeout_i > 0 and color != "red":
|
||||
color = "#b58900"
|
||||
self.lbl_dns_resolver_health.setText(
|
||||
f"Resolver health: avg={avg}ms ok={ok_i} fail={fail_i} timeout={timeout_i}"
|
||||
)
|
||||
self.lbl_dns_resolver_health.setStyleSheet(f"color: {color};")
|
||||
|
||||
def _set_traffic_mode_state(
|
||||
self,
|
||||
desired_mode: str,
|
||||
applied_mode: str,
|
||||
preferred_iface: str,
|
||||
advanced_active: bool,
|
||||
auto_local_bypass: bool,
|
||||
auto_local_active: bool,
|
||||
ingress_reply_bypass: bool,
|
||||
ingress_reply_active: bool,
|
||||
bypass_candidates: int,
|
||||
overrides_applied: int,
|
||||
cgroup_resolved_uids: int,
|
||||
cgroup_warning: str,
|
||||
healthy: bool,
|
||||
ingress_rule_present: bool,
|
||||
ingress_nft_active: bool,
|
||||
probe_ok: bool,
|
||||
probe_message: str,
|
||||
active_iface: str,
|
||||
@@ -763,9 +801,17 @@ RU: Источник wildcard IP: резолвер, runtime nftset SmartDNS, и
|
||||
diag_parts = []
|
||||
diag_parts.append(f"preferred={preferred_iface or 'auto'}")
|
||||
diag_parts.append(
|
||||
f"auto_local_bypass={'on' if auto_local_bypass else 'off'}"
|
||||
f"advanced={'on' if advanced_active else 'off'}"
|
||||
)
|
||||
if bypass_candidates > 0:
|
||||
diag_parts.append(
|
||||
f"auto_local={'on' if auto_local_bypass else 'off'}"
|
||||
f"({'active' if auto_local_active else 'saved'})"
|
||||
)
|
||||
diag_parts.append(
|
||||
f"ingress_reply={'on' if ingress_reply_bypass else 'off'}"
|
||||
f"({'active' if ingress_reply_active else 'saved'})"
|
||||
)
|
||||
if auto_local_active and bypass_candidates > 0:
|
||||
diag_parts.append(f"bypass_routes={bypass_candidates}")
|
||||
diag_parts.append(f"overrides={overrides_applied}")
|
||||
if cgroup_resolved_uids > 0:
|
||||
@@ -776,6 +822,10 @@ RU: Источник wildcard IP: резолвер, runtime nftset SmartDNS, и
|
||||
diag_parts.append(f"iface={active_iface}")
|
||||
if iface_reason:
|
||||
diag_parts.append(f"source={iface_reason}")
|
||||
diag_parts.append(
|
||||
f"ingress_diag=rule:{'ok' if ingress_rule_present else 'off'}"
|
||||
f"/nft:{'ok' if ingress_nft_active else 'off'}"
|
||||
)
|
||||
diag_parts.append(f"probe={'ok' if probe_ok else 'fail'}")
|
||||
if probe_message:
|
||||
diag_parts.append(probe_message)
|
||||
@@ -998,12 +1048,18 @@ RU: Источник wildcard IP: резолвер, runtime nftset SmartDNS, и
|
||||
t.desired_mode,
|
||||
t.applied_mode,
|
||||
t.preferred_iface,
|
||||
bool(t.advanced_active),
|
||||
bool(t.auto_local_bypass),
|
||||
bool(t.auto_local_active),
|
||||
bool(t.ingress_reply_bypass),
|
||||
bool(t.ingress_reply_active),
|
||||
int(t.bypass_candidates),
|
||||
int(t.overrides_applied),
|
||||
int(t.cgroup_resolved_uids),
|
||||
t.cgroup_warning,
|
||||
bool(t.healthy),
|
||||
bool(t.ingress_rule_present),
|
||||
bool(t.ingress_nft_active),
|
||||
bool(t.probe_ok),
|
||||
t.probe_message,
|
||||
t.active_iface,
|
||||
@@ -1017,10 +1073,7 @@ RU: Источник wildcard IP: резолвер, runtime nftset SmartDNS, и
|
||||
self._dns_ui_refresh = True
|
||||
try:
|
||||
ups = self.ctrl.dns_upstreams_view()
|
||||
self.ent_def1.setText(ups.default1 or "")
|
||||
self.ent_def2.setText(ups.default2 or "")
|
||||
self.ent_meta1.setText(ups.meta1 or "")
|
||||
self.ent_meta2.setText(ups.meta2 or "")
|
||||
self._set_dns_resolver_summary(ups)
|
||||
|
||||
st = self.ctrl.dns_status_view()
|
||||
self.ent_smartdns_addr.setText(st.smartdns_addr or "")
|
||||
@@ -1037,12 +1090,6 @@ RU: Источник wildcard IP: резолвер, runtime nftset SmartDNS, и
|
||||
self.chk_dns_via_smartdns.setChecked(hybrid_enabled)
|
||||
self.chk_dns_via_smartdns.blockSignals(False)
|
||||
|
||||
# In direct + hybrid modes upstreams stay editable.
|
||||
self.ent_def1.setEnabled(True)
|
||||
self.ent_def2.setEnabled(True)
|
||||
self.ent_meta1.setEnabled(True)
|
||||
self.ent_meta2.setEnabled(True)
|
||||
|
||||
unit_state = (st.unit_state or "unknown").strip().lower()
|
||||
unit_active = unit_state == "active"
|
||||
self.chk_dns_unit_relay.blockSignals(True)
|
||||
@@ -1386,13 +1433,6 @@ RU: Источник wildcard IP: резолвер, runtime nftset SmartDNS, и
|
||||
def work():
|
||||
if self._dns_ui_refresh:
|
||||
return
|
||||
ups = DnsUpstreams(
|
||||
default1=self.ent_def1.text().strip(),
|
||||
default2=self.ent_def2.text().strip(),
|
||||
meta1=self.ent_meta1.text().strip(),
|
||||
meta2=self.ent_meta2.text().strip(),
|
||||
)
|
||||
self.ctrl.dns_upstreams_save(ups)
|
||||
self.ctrl.dns_mode_set(
|
||||
self.chk_dns_via_smartdns.isChecked(),
|
||||
self.ent_smartdns_addr.text().strip(),
|
||||
@@ -1400,6 +1440,18 @@ RU: Источник wildcard IP: резолвер, runtime nftset SmartDNS, и
|
||||
self.ctrl.log_gui("DNS settings autosaved")
|
||||
self._safe(work, title="DNS save error")
|
||||
|
||||
def on_open_dns_benchmark(self) -> None:
|
||||
def work():
|
||||
dlg = DNSBenchmarkDialog(
|
||||
self.ctrl,
|
||||
settings=self._ui_settings,
|
||||
refresh_cb=self.refresh_dns_tab,
|
||||
parent=self,
|
||||
)
|
||||
dlg.exec()
|
||||
self.refresh_dns_tab()
|
||||
self._safe(work, title="DNS benchmark error")
|
||||
|
||||
def on_dns_mode_toggle(self) -> None:
|
||||
def work():
|
||||
via = self.chk_dns_via_smartdns.isChecked()
|
||||
|
||||
Reference in New Issue
Block a user