- Backend: ConfigManager write methods (atomic YAML save), admin CRUD router for settings (display/odoo/refresh) and nodes, WS broadcast on config changes, fix nmap scan blocking event loop with to_thread - Frontend: admin UI with tab navigation, overview dashboard, node CRUD table with modal form, Odoo/display/refresh settings pages, typed API wrappers, active views filtering, config_changed WS handler - Infra: nginx no-cache headers for HTML, cache-forever for hashed assets - Fixes: WebSocket reconnect loop (ref pattern), rotation index OOB when views shrink, mutable node list cache Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
39 lines
1.3 KiB
Python
39 lines
1.3 KiB
Python
import asyncio
|
|
|
|
from fastapi import APIRouter, Depends
|
|
from modules.config_manager import ConfigManager
|
|
from modules.network_scanner import NetworkScanner
|
|
|
|
router = APIRouter(prefix="/api/network", tags=["network"])
|
|
|
|
|
|
def get_config() -> ConfigManager:
|
|
from main import app_config
|
|
return app_config
|
|
|
|
|
|
@router.get("/topology")
|
|
async def get_topology(config: ConfigManager = Depends(get_config)):
|
|
scan_config = config.get_network_scan_config()
|
|
configured_nodes = config.get_nodes()
|
|
|
|
scanner = NetworkScanner(subnet=scan_config.get("subnet", "192.168.1.0/24"))
|
|
|
|
if scan_config.get("enabled", False):
|
|
try:
|
|
scan_data = await asyncio.to_thread(scanner.scan)
|
|
discovered = scanner.parse_scan_results(scan_data)
|
|
nodes = scanner.merge_with_config(discovered, configured_nodes)
|
|
except Exception:
|
|
nodes = [{**n, "status": "unknown"} for n in configured_nodes]
|
|
else:
|
|
nodes = [{**n, "status": "unknown"} for n in configured_nodes]
|
|
|
|
# Ping all nodes for current status
|
|
ips = [n["ip"] for n in nodes]
|
|
statuses = await scanner.ping_all(ips)
|
|
for node in nodes:
|
|
node["status"] = "up" if statuses.get(node["ip"], False) else "down"
|
|
|
|
return {"nodes": nodes, "scan_enabled": scan_config.get("enabled", False)}
|