Files
vps_monitoring/server/main.py
Андрей Бобырев 1c4f97124a feat: keenetic integration, VPN alerts, docs
Wire keenetic monitor loop and router into main app. Add deduplicated
Telegram alerts for router offline, internet, CPU/RAM, and VPN down.
Update README with KeenDNS edit, import format, troubleshooting.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 01:55:03 +03:00

118 lines
3.7 KiB
Python

import asyncio
import logging
import os
import sys
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from contextlib import asynccontextmanager
# Add parent to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from server.auth import get_current_user
from server.api.servers import router as servers_router
from server.api.auth_routes import router as auth_router
from server.api.ssh_ws import router as ssh_router
from server.api.pc import router as pc_router
from server.api.synology import router as synology_router
from server.api.ha import router as ha_router
from server.api.keenetic import router as keenetic_router, keenetic_monitor_loop
from server.api.notifications import router as notifications_router
from server.services.monitor import monitor_loop
from server.services.telegram_bot import start_bot, stop_bot
from server.services.alerter import check_alerts
from server.config import load_settings
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
monitor_task = None
alert_task = None
keenetic_task = None
async def alert_loop():
"""Periodic alert checking."""
while True:
try:
await check_alerts()
except Exception as e:
logger.error(f"Alert check error: {e}")
await asyncio.sleep(60)
@asynccontextmanager
async def lifespan(app: FastAPI):
global monitor_task, alert_task, keenetic_task
monitor_task = asyncio.create_task(monitor_loop())
alert_task = asyncio.create_task(alert_loop())
keenetic_task = asyncio.create_task(keenetic_monitor_loop())
await start_bot()
logger.info("VPS Monitoring started")
yield
if monitor_task:
monitor_task.cancel()
if alert_task:
alert_task.cancel()
if keenetic_task:
keenetic_task.cancel()
await stop_bot()
app = FastAPI(title="VPS Monitoring", lifespan=lifespan)
# Static files
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
templates = Jinja2Templates(directory=os.path.join(BASE_DIR, "templates"))
# Static downloads (Windows agent) — mount BEFORE /static to avoid prefix conflict
DOWNLOADS_DIR = os.path.join(os.path.dirname(BASE_DIR), "windows")
if os.path.isdir(DOWNLOADS_DIR):
app.mount("/static/downloads", StaticFiles(directory=DOWNLOADS_DIR), name="downloads")
app.mount("/static", StaticFiles(directory=os.path.join(BASE_DIR, "static")), name="static")
# Include routers
app.include_router(servers_router)
app.include_router(auth_router)
app.include_router(ssh_router)
app.include_router(pc_router)
app.include_router(synology_router)
app.include_router(ha_router)
app.include_router(keenetic_router)
app.include_router(notifications_router)
@app.get("/", response_class=HTMLResponse)
async def dashboard(request: Request):
user = get_current_user(request)
if not user:
return RedirectResponse("/login")
return templates.TemplateResponse("dashboard.html", {"request": request})
@app.get("/login", response_class=HTMLResponse)
async def login_page(request: Request):
user = get_current_user(request)
if user:
return RedirectResponse("/")
return templates.TemplateResponse("login.html", {"request": request})
@app.get("/telegram-app", response_class=HTMLResponse)
async def telegram_app(request: Request):
return templates.TemplateResponse("telegram_app.html", {"request": request})
@app.get("/api/health")
async def health():
return {"status": "ok", "version": "1.0.0"}
if __name__ == "__main__":
import uvicorn
uvicorn.run("server.main:app", host="0.0.0.0", port=7272, reload=True)