Skip to content
This repository was archived by the owner on Jan 14, 2026. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 70 additions & 31 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -638,9 +638,10 @@ def __init__(self, root):
self.var_dark_mode = tk.BooleanVar(value=True)

# --- Proxy monitoring vars ---
default_proxy_text = (
f"Proxies loaded: {self.proxy_pool.total} (ready)" if self._proxy_enabled else "Proxies disabled"
)
if self.proxy_pool:
default_proxy_text = f"Proxies loaded: {self.proxy_pool.total} (0 available)"
else:
default_proxy_text = "Proxies disabled"
self.var_proxy_summary = tk.StringVar(value=default_proxy_text)
self.var_proxy_health_hint = tk.StringVar(value="")

Expand Down Expand Up @@ -1049,6 +1050,10 @@ def _init_proxy_pool(self):
pool = None
if pool:
self.proxy_pool = pool
try:
self.proxy_pool.prepare_for_run()
except Exception:
pass
self._proxy_enabled = True
self._uiq_put(("log", f"[PROXY] Loaded {pool.total} Mullvad proxy endpoints.", "info"))
else:
Expand All @@ -1075,9 +1080,19 @@ def toggle_proxy_usage(self):
return
self._proxy_enabled = not self._proxy_enabled
if self._proxy_enabled:
self.proxy_pool.prepare_for_run()
self._proxy_log("[PROXY] Proxy usage enabled.", "info")
self.var_proxy_health_hint.set("Proxy usage enabled")
try:
self.proxy_pool.prepare_for_run()
except Exception:
pass
snapshot = []
try:
snapshot = self.proxy_pool.snapshot_health()
except Exception:
snapshot = []
healthy = sum(1 for entry in snapshot if entry.get("health_ok"))
total = len(snapshot)
self._proxy_log(f"[PROXY] Proxy usage enabled. Healthy {healthy}/{total} endpoints.", "info")
self.var_proxy_health_hint.set("OK" if healthy else "High failures")
else:
self._proxy_log("[PROXY] Proxy usage disabled.", "info")
self.var_proxy_health_hint.set("Proxy usage disabled")
Expand Down Expand Up @@ -1468,6 +1483,12 @@ def _handle_vpn_status_update(self, status: dict):
self._ctl_async(msg)
if connected_bool is not None:
self._vpn_connected = connected_bool
if self.proxy_pool:
try:
self.proxy_pool.set_mullvad_connected(connected_bool)
except Exception:
pass
self._run_on_ui(self._refresh_proxy_health_ui)

self._run_on_ui(self._update_mullvad_label)

Expand Down Expand Up @@ -2455,6 +2476,21 @@ def _handle_proxy_event_ui(self, event: dict) -> None:
latency = event.get("latency_ms")
if latency is not None:
self.var_proxy_health_hint.set(f"{label} success {latency:.1f} ms")
elif kind == "health":
ok = bool(event.get("ok"))
latency = event.get("latency_ms")
country = event.get("country")
if ok:
latency_text = f"{latency:.1f} ms" if latency is not None else "-"
detail = f"[PROXY] {label} health OK ({latency_text})"
if country:
detail += f" [{country}]"
self._proxy_log(detail, "success")
self.var_proxy_health_hint.set("OK")
else:
error = event.get("error") or "health probe failed"
self._proxy_log(f"[PROXY] {label} health failed: {error}", "warn")
self.var_proxy_health_hint.set("High failures")
elif kind == "proxy-quarantine":
duration = float(event.get("duration") or 0.0)
consecutive = event.get("consecutive")
Expand Down Expand Up @@ -2484,39 +2520,37 @@ def _refresh_proxy_health_ui(self):
self.var_proxy_health_hint.set("")
self._update_proxy_toggle_button()
return
snapshot = self.proxy_pool.health_snapshot()
try:
snapshot = self.proxy_pool.snapshot_health()
except Exception:
snapshot = []
self._proxy_snapshot = snapshot
total = len(snapshot)
in_use = sum(1 for item in snapshot if item.get("in_use"))
disabled_count = sum(1 for item in snapshot if (item.get("disabled") or 0) > 0.05)
quarantine_count = sum(
healthy = sum(1 for item in snapshot if item.get("health_ok"))
healthy_ratio = (healthy / total) if total else 0.0
available = sum(
1
for item in snapshot
if (item.get("quarantine") or 0) > 0.05 and (item.get("disabled") or 0) <= 0.05
if not item.get("in_use")
and (item.get("status") == "OK")
and bool(item.get("health_ok"))
)
cooling = sum(
1
for item in snapshot
if (
not item.get("in_use")
and (item.get("cooldown") or 0) > 0.05
and (item.get("quarantine") or 0) <= 0.05
and (item.get("disabled") or 0) <= 0.05
)
)
idle = max(0, total - in_use - cooling - quarantine_count - disabled_count)
summary_parts = [f"Proxies {total}", f"in use {in_use}"]
if disabled_count:
summary_parts.append(f"disabled {disabled_count}")
if quarantine_count:
summary_parts.append(f"quarantine {quarantine_count}")
if cooling:
summary_parts.append(f"cooling {cooling}")
summary_parts.append(f"idle {idle}")
summary = " | ".join(summary_parts)
summary = f"Proxies loaded: {total} ({available} available)"
if not self._proxy_enabled:
summary += " (disabled)"
self.var_proxy_summary.set(summary)
pool_connected = getattr(self.proxy_pool, "mullvad_connected", True)
if not self._proxy_enabled:
hint = "Proxy usage disabled"
elif not pool_connected:
hint = "Mullvad disconnected"
elif healthy_ratio < 0.4:
hint = "High failures"
elif total == 0:
hint = "High failures"
else:
hint = "OK"
self.var_proxy_health_hint.set(hint)
existing = set(self.proxy_tree.get_children())
for item_id in existing:
self.proxy_tree.delete(item_id)
Expand All @@ -2543,6 +2577,11 @@ def _refresh_proxy_health_ui(self):
status = f"Cooling {cooldown:.1f}s"
else:
status = "Idle"
health_ok = bool(entry.get("health_ok"))
health_fresh = bool(entry.get("health_fresh"))
if not health_ok:
status_suffix = "health fail" if health_fresh else "health stale"
status = f"{status} ({status_suffix})"
last_stage = entry.get("last_stage")
last_error = entry.get("last_error")
if last_error and not in_use_flag:
Expand Down
Loading