初始化奇妙小屏幕控制器项目
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import socket
|
||||
import ssl
|
||||
import subprocess
|
||||
import time
|
||||
from copy import deepcopy
|
||||
from typing import Any, Callable
|
||||
|
||||
|
||||
class NetworkDiagnostics:
|
||||
def __init__(
|
||||
self,
|
||||
status_provider: Callable[[], dict[str, Any]],
|
||||
*,
|
||||
runner=subprocess.run,
|
||||
resolver=socket.getaddrinfo,
|
||||
connector=socket.create_connection,
|
||||
) -> None:
|
||||
self.status_provider = status_provider
|
||||
self.runner = runner
|
||||
self.resolver = resolver
|
||||
self.connector = connector
|
||||
|
||||
@staticmethod
|
||||
def _check(code: str, ok: bool, message: str, *, warning: bool = False) -> dict[str, Any]:
|
||||
return {"code": code, "ok": ok, "warning": warning, "message": message}
|
||||
|
||||
def _command(self, command: list[str], timeout: int = 3) -> subprocess.CompletedProcess[str] | None:
|
||||
try:
|
||||
return self.runner(command, capture_output=True, text=True, timeout=timeout)
|
||||
except (OSError, subprocess.TimeoutExpired):
|
||||
return None
|
||||
|
||||
def run(self) -> dict[str, Any]:
|
||||
started = time.monotonic()
|
||||
checks: list[dict[str, Any]] = []
|
||||
active = (self.status_provider().get("active") or {})
|
||||
connected = active.get("connected") is True and bool(active.get("ipv4_address"))
|
||||
checks.append(self._check("interface", connected, "网络接口已连接" if connected else "网卡或 WiFi 未连接"))
|
||||
if not connected:
|
||||
return self._result(checks, started, "failed", "网卡或 WiFi 未连接")
|
||||
|
||||
route = self._command(["/usr/sbin/ip", "-4", "route", "show", "default"])
|
||||
route_ok = bool(route and route.returncode == 0 and route.stdout.strip())
|
||||
checks.append(self._check("default_route", route_ok, "默认路由正常" if route_ok else "默认网关缺失"))
|
||||
if not route_ok:
|
||||
return self._result(checks, started, "failed", "默认网关缺失")
|
||||
|
||||
dns_ok = False
|
||||
for host in ("www.baidu.com", "www.qq.com"):
|
||||
try:
|
||||
if self.resolver(host, 443, type=socket.SOCK_STREAM):
|
||||
dns_ok = True
|
||||
break
|
||||
except OSError:
|
||||
continue
|
||||
checks.append(self._check("dns", dns_ok, "DNS 解析正常" if dns_ok else "DNS 解析失败"))
|
||||
if not dns_ok:
|
||||
return self._result(checks, started, "failed", "DNS 解析失败,请检查 DNS 或网关配置")
|
||||
|
||||
reachable = False
|
||||
tls_ok = False
|
||||
for host in ("www.baidu.com", "www.qq.com"):
|
||||
try:
|
||||
raw = self.connector((host, 443), timeout=3)
|
||||
reachable = True
|
||||
try:
|
||||
context = ssl.create_default_context()
|
||||
with context.wrap_socket(raw, server_hostname=host):
|
||||
tls_ok = True
|
||||
break
|
||||
finally:
|
||||
try:
|
||||
raw.close()
|
||||
except OSError:
|
||||
pass
|
||||
except (OSError, ssl.SSLError):
|
||||
continue
|
||||
checks.append(self._check("internet", reachable, "外网 TCP 连接正常" if reachable else "网关或上游网络不可达"))
|
||||
checks.append(self._check("tls", tls_ok, "TLS 校验正常" if tls_ok else "TLS 或系统时间可能异常"))
|
||||
|
||||
ping = self._command(["/usr/bin/ping", "-c", "1", "-W", "2", "www.baidu.com"])
|
||||
ping_ok = bool(ping and ping.returncode == 0)
|
||||
checks.append(self._check(
|
||||
"icmp", ping_ok,
|
||||
"百度 ping 正常" if ping_ok else "目标未响应 ping;部分网络会屏蔽 ICMP",
|
||||
warning=not ping_ok and tls_ok,
|
||||
))
|
||||
if tls_ok:
|
||||
return self._result(checks, started, "ok", "网络连接正常")
|
||||
if reachable:
|
||||
return self._result(checks, started, "failed", "TLS 或系统时间可能异常")
|
||||
return self._result(checks, started, "failed", "网关或上游网络不可达")
|
||||
|
||||
@staticmethod
|
||||
def _result(checks: list[dict[str, Any]], started: float, overall: str, diagnosis: str) -> dict[str, Any]:
|
||||
return {
|
||||
"overall": overall,
|
||||
"diagnosis": diagnosis,
|
||||
"duration_ms": int((time.monotonic() - started) * 1000),
|
||||
"checks": checks,
|
||||
}
|
||||
|
||||
|
||||
class MockNetworkDiagnostics:
|
||||
def __init__(self, result: dict[str, Any] | None = None) -> None:
|
||||
self.result = result or {
|
||||
"overall": "ok",
|
||||
"diagnosis": "网络连接正常(mock)",
|
||||
"duration_ms": 1,
|
||||
"checks": [
|
||||
{"code": "interface", "ok": True, "warning": False, "message": "网络接口已连接"},
|
||||
{"code": "dns", "ok": True, "warning": False, "message": "DNS 解析正常"},
|
||||
{"code": "internet", "ok": True, "warning": False, "message": "外网连接正常"},
|
||||
],
|
||||
}
|
||||
|
||||
def run(self) -> dict[str, Any]:
|
||||
return deepcopy(self.result)
|
||||
Reference in New Issue
Block a user