mirror of
https://github.com/anten-ka/gotelegram_pro.git
synced 2026-05-19 20:36:04 +00:00
v2.5.0: redesign local admin and repair stats
This commit is contained in:
@@ -69,6 +69,18 @@ def load_json(path: Path, fallback: Any = None) -> Any:
|
||||
return fallback
|
||||
|
||||
|
||||
def read_language(config: dict[str, Any] | None = None) -> str:
|
||||
config = config or load_json(GOTELEGRAM_CONFIG, {}) or {}
|
||||
lang = str(config.get("language") or config.get("lang") or "").strip().lower()
|
||||
marker = INSTALL_DIR / ".language"
|
||||
if lang not in {"en", "ru"} and marker.exists():
|
||||
try:
|
||||
lang = marker.read_text(encoding="utf-8", errors="ignore").strip().lower()[:2]
|
||||
except OSError:
|
||||
lang = ""
|
||||
return lang if lang in {"en", "ru"} else "en"
|
||||
|
||||
|
||||
def read_telemt_users() -> dict[str, str]:
|
||||
if not TELEMT_CONFIG.exists():
|
||||
return {}
|
||||
@@ -257,6 +269,74 @@ def load_stats_history(limit: int = 240) -> list[dict[str, int]]:
|
||||
return enriched
|
||||
|
||||
|
||||
def count_history_rows() -> int:
|
||||
if not HISTORY_FILE.exists():
|
||||
return 0
|
||||
try:
|
||||
with HISTORY_FILE.open("r", encoding="utf-8", errors="ignore") as fh:
|
||||
return sum(1 for line in fh if line and line[0].isdigit())
|
||||
except OSError:
|
||||
return 0
|
||||
|
||||
|
||||
def stats_status(current: dict[str, Any] | None = None, history: list[dict[str, int]] | None = None) -> dict[str, Any]:
|
||||
current = current if current is not None else (load_json(CURRENT_STATS, {}) or {})
|
||||
history = history if history is not None else load_stats_history(limit=2)
|
||||
service = service_status("gotelegram-stats")
|
||||
now = int(time.time())
|
||||
ts = int(current.get("ts") or 0) if isinstance(current, dict) else 0
|
||||
age = max(0, now - ts) if ts else None
|
||||
error = str(current.get("error") or "") if isinstance(current, dict) else ""
|
||||
history_rows = count_history_rows()
|
||||
if error:
|
||||
health = "error"
|
||||
elif service == "running" and current and age is not None and age <= 180:
|
||||
health = "ok"
|
||||
elif service == "running":
|
||||
health = "stale"
|
||||
elif service == "not_installed":
|
||||
health = "not_installed"
|
||||
else:
|
||||
health = "stopped"
|
||||
return {
|
||||
"health": health,
|
||||
"service": service,
|
||||
"current_exists": CURRENT_STATS.exists(),
|
||||
"history_exists": HISTORY_FILE.exists(),
|
||||
"history_rows": history_rows,
|
||||
"history_points": len(history or []),
|
||||
"last_ts": ts,
|
||||
"age_seconds": age,
|
||||
"error": error,
|
||||
}
|
||||
|
||||
|
||||
def run_stats_action(action: str) -> tuple[bool, str, dict[str, Any]]:
|
||||
if action == "repair":
|
||||
body = (
|
||||
"source /opt/gotelegram/lib/common.sh; "
|
||||
"source /opt/gotelegram/lib/i18n.sh; "
|
||||
"source /opt/gotelegram/lib/stats.sh; "
|
||||
"load_language \"$(detect_language 2>/dev/null || echo en)\"; "
|
||||
"install_stats_collector; "
|
||||
"stats_collect"
|
||||
)
|
||||
timeout = 180
|
||||
else:
|
||||
body = (
|
||||
"source /opt/gotelegram/lib/common.sh; "
|
||||
"source /opt/gotelegram/lib/stats.sh; "
|
||||
"stats_init >/dev/null 2>&1 || true; "
|
||||
"stats_collect"
|
||||
)
|
||||
timeout = 30
|
||||
code, stdout, stderr = run(["bash", "-lc", body], timeout=timeout)
|
||||
message = (stdout.strip().splitlines()[-1:] or stderr.strip().splitlines()[-1:] or [""])[0]
|
||||
current = load_json(CURRENT_STATS, {}) or {}
|
||||
history = load_stats_history()
|
||||
return code == 0, message, {"current": current, "history": history, "status": stats_status(current, history)}
|
||||
|
||||
|
||||
def list_backups() -> list[dict[str, Any]]:
|
||||
if not BACKUP_DIR.exists():
|
||||
return []
|
||||
@@ -307,8 +387,10 @@ def user_payload(name: str, secret: str, include_runtime: bool = False) -> dict[
|
||||
|
||||
def overview_payload() -> dict[str, Any]:
|
||||
config = load_json(GOTELEGRAM_CONFIG, {}) or {}
|
||||
language = read_language(config)
|
||||
users = read_telemt_users()
|
||||
current = load_json(CURRENT_STATS, {}) or {}
|
||||
history = load_stats_history()
|
||||
summary = telemt_api("/v1/stats/summary")
|
||||
services = {
|
||||
"telemt": service_status("telemt"),
|
||||
@@ -320,11 +402,14 @@ def overview_payload() -> dict[str, Any]:
|
||||
return {
|
||||
"version": VERSION,
|
||||
"time": utc_now(),
|
||||
"language": language,
|
||||
"admin_bind": {"host": HOST, "port": PORT},
|
||||
"config": config,
|
||||
"users_count": len(users),
|
||||
"services": services,
|
||||
"stats_current": current,
|
||||
"stats_history": load_stats_history(),
|
||||
"stats_history": history,
|
||||
"stats_status": stats_status(current, history),
|
||||
"runtime_summary": summary,
|
||||
"backups": list_backups(),
|
||||
}
|
||||
@@ -378,6 +463,10 @@ class AdminHandler(BaseHTTPRequestHandler):
|
||||
self.send_json({"ok": True, "data": user_payload(name, users[name], include_runtime=True)})
|
||||
elif path == "/api/backups":
|
||||
self.send_json({"ok": True, "data": list_backups()})
|
||||
elif path == "/api/stats":
|
||||
current = load_json(CURRENT_STATS, {}) or {}
|
||||
history = load_stats_history()
|
||||
self.send_json({"ok": True, "data": {"current": current, "history": history, "status": stats_status(current, history)}})
|
||||
elif path == "/api/logs":
|
||||
qs = urllib.parse.parse_qs(parsed.query)
|
||||
service = qs.get("service", ["telemt"])[0]
|
||||
@@ -422,6 +511,14 @@ class AdminHandler(BaseHTTPRequestHandler):
|
||||
elif path == "/api/backups":
|
||||
ok, result = create_backup()
|
||||
self.send_json({"ok": ok, "data": {"path": result, "backups": list_backups()}}, 200 if ok else 500)
|
||||
elif path == "/api/stats/collect":
|
||||
ok, message, payload = run_stats_action("collect")
|
||||
payload["message"] = message
|
||||
self.send_json({"ok": ok, "data": payload}, 200 if ok else 500)
|
||||
elif path == "/api/stats/repair":
|
||||
ok, message, payload = run_stats_action("repair")
|
||||
payload["message"] = message
|
||||
self.send_json({"ok": ok, "data": payload}, 200 if ok else 500)
|
||||
elif path.startswith("/api/services/") and path.endswith("/restart"):
|
||||
service = path[len("/api/services/"):-len("/restart")]
|
||||
allowed = {"telemt", "nginx", "gotelegram-bot", "gotelegram-stats"}
|
||||
|
||||
Reference in New Issue
Block a user