aa8af6c2e0
Flask + SQLite + Bootstrap5 暗色主题 - 仪表盘: 在线/离线统计 + 最近代理 + 操作日志 - 代理 CRUD: 增删改 + 启用/禁用 + 单/批量健康检测(SOCKS5) - 分组管理: 创建/删除/筛选 - 操作日志: 分页查询 - RESTful API + Web 界面 - 管理员登录认证 (SM_ADMIN_PASSWORD 环境变量)
87 lines
2.5 KiB
Python
87 lines
2.5 KiB
Python
import time
|
||
import logging
|
||
from datetime import datetime, timezone
|
||
|
||
from models import Proxy, db
|
||
from extensions import db as _db_ext
|
||
|
||
log = logging.getLogger("socks.health")
|
||
|
||
TEST_URL = "http://httpbin.org/get"
|
||
|
||
|
||
def check_proxy(proxy):
|
||
"""检查单个 SOCKS5 代理是否可用。返回 {status, latency_ms, error}"""
|
||
import socks
|
||
import socket
|
||
|
||
host, port = proxy.host, proxy.port
|
||
timeout = 10
|
||
status = "unknown"
|
||
latency = None
|
||
error = None
|
||
|
||
orig_getaddrinfo = socket.getaddrinfo
|
||
orig_socket = socket.socket
|
||
|
||
try:
|
||
# 使用 PySocks 创建 SOCKS5 隧道
|
||
s = socks.socksocket()
|
||
s.settimeout(timeout)
|
||
s.set_proxy(socks.SOCKS5, host, port,
|
||
username=proxy.username or None,
|
||
password=proxy.password or None)
|
||
|
||
t0 = time.time()
|
||
# 尝试连接到测试 URL(httpbin.org)
|
||
s.connect(("httpbin.org", 80))
|
||
elapsed = time.time() - t0
|
||
latency = round(elapsed * 1000, 1)
|
||
|
||
# 发送一个简单 HTTP HEAD 请求验证隧道通畅
|
||
s.sendall(b"HEAD /get HTTP/1.1\r\nHost: httpbin.org\r\nConnection: close\r\n\r\n")
|
||
resp = s.recv(1024)
|
||
s.close()
|
||
|
||
if resp and (b"200" in resp[:4] or b"301" in resp[:4] or b"302" in resp[:4]):
|
||
status = "online"
|
||
else:
|
||
status = "online" # 连接成功即算在线(某些代理只允许特定目标)
|
||
|
||
except Exception as e:
|
||
status = "offline"
|
||
error = str(e)[:200]
|
||
log.warning("Proxy %s:%d check failed: %s", host, port, e)
|
||
finally:
|
||
socket.getaddrinfo = orig_getaddrinfo
|
||
socket.socket = orig_socket
|
||
|
||
return {"status": status, "latency_ms": latency, "error": error}
|
||
|
||
|
||
def run_health_checks():
|
||
"""对所有 enabled 的代理运行健康检测,更新数据库,返回结果摘要。"""
|
||
proxies = Proxy.query.filter_by(enabled=True).all()
|
||
results = []
|
||
online_count = 0
|
||
|
||
for p in proxies:
|
||
r = check_proxy(p)
|
||
p.status = r["status"]
|
||
p.latency_ms = r["latency_ms"]
|
||
p.last_check = datetime.now(timezone.utc)
|
||
if r["status"] == "online":
|
||
online_count += 1
|
||
results.append({
|
||
"id": p.id, "name": p.name, "host": p.host, "port": p.port,
|
||
**r,
|
||
})
|
||
|
||
_db_ext.session.commit()
|
||
return {
|
||
"checked": len(results),
|
||
"online": online_count,
|
||
"offline": len(results) - online_count,
|
||
"details": results,
|
||
}
|