"""MY Network Monitoring Sanic Blueprint - веб-интерфейс мониторинга сети.""" import asyncio import json import logging from datetime import datetime, timedelta from typing import Dict, List, Any from pathlib import Path from sanic import Blueprint, Request from sanic.response import json as json_response, html as html_response from sanic.exceptions import SanicException from app.core.logging import get_logger logger = get_logger(__name__) # Создать blueprint для мониторинга bp = Blueprint("my_monitoring", url_prefix="/api/my/monitor") def get_node_service(): """Получить сервис ноды.""" try: from app.core.my_network.node_service import get_node_service return get_node_service() except Exception as e: logger.error(f"Error getting node service: {e}") return None @bp.get("/") async def monitoring_dashboard(request: Request): """Главная страница мониторинга MY Network.""" try: # Получить данные для дашборда node_service = get_node_service() if not node_service: monitoring_data = { "status": "offline", "error": "MY Network service not available" } else: # Собрать данные со всех компонентов node_info = await node_service.get_node_info() peers_info = await node_service.get_peers_info() sync_status = await node_service.sync_manager.get_sync_status() monitoring_data = { "status": "online", "node_info": node_info, "peers_info": peers_info, "sync_status": sync_status, "timestamp": datetime.utcnow().isoformat() } # Попробовать использовать шаблон try: from jinja2 import Environment, FileSystemLoader # Настроить Jinja2 templates_dir = Path(__file__).parent.parent.parent / "templates" if templates_dir.exists(): env = Environment(loader=FileSystemLoader(str(templates_dir))) template = env.get_template("my_network_monitor.html") html_content = template.render(monitoring_data=monitoring_data) return html_response(html_content) except Exception as e: logger.warning(f"Template rendering failed: {e}") # Fallback HTML если шаблоны не работают return html_response(generate_fallback_html(monitoring_data)) except Exception as e: logger.error(f"Error rendering monitoring dashboard: {e}") return html_response(generate_fallback_html({"status": "error", "error": str(e)})) @bp.get("/ascii") async def get_ascii_status(request: Request): """Получить ASCII статус сети.""" try: node_service = get_node_service() if not node_service: return json_response({"ascii": generate_offline_ascii(), "status": "offline"}) # Получить данные node_info = await node_service.get_node_info() peers_info = await node_service.get_peers_info() sync_status = await node_service.sync_manager.get_sync_status() # Генерировать ASCII ascii_art = await generate_network_ascii(node_info, peers_info, sync_status) return json_response({ "ascii": ascii_art, "status": "online", "timestamp": datetime.utcnow().isoformat() }) except Exception as e: logger.error(f"Error generating ASCII status: {e}") return json_response({"ascii": generate_error_ascii(str(e)), "status": "error"}) @bp.get("/live") async def live_monitoring_data(request: Request): """Получить живые данные для мониторинга.""" try: node_service = get_node_service() if not node_service: return json_response( {"error": "MY Network service unavailable"}, status=503 ) # Получить свежие данные node_info = await node_service.get_node_info() peers_info = await node_service.get_peers_info() sync_status = await node_service.sync_manager.get_sync_status() # Статистика сети network_stats = { "connected_peers": peers_info["peer_count"], "active_syncs": sync_status["active_syncs"], "queue_size": sync_status["queue_size"], "uptime": node_info["uptime"], "status": node_info["status"] } return json_response({ "success": True, "data": { "node_info": node_info, "network_stats": network_stats, "peers": peers_info["peers"][:10], # Показать только первые 10 пиров "sync_status": sync_status }, "timestamp": datetime.utcnow().isoformat() }) except Exception as e: logger.error(f"Error getting live monitoring data: {e}") return json_response({"error": str(e)}, status=500) async def generate_network_ascii(node_info: Dict[str, Any], peers_info: Dict[str, Any], sync_status: Dict[str, Any]) -> str: """Генерировать ASCII представление состояния сети.""" ascii_parts = [] # Заголовок ascii_parts.append(""" ╔══════════════════════════════════════════════════════════════════════════════╗ ║ MY NETWORK v2.0 ║ ║ Distributed Content Protocol ║ ╚══════════════════════════════════════════════════════════════════════════════╝ """) # Информация о ноде status_indicator = "🟢" if node_info.get("status") == "running" else "🔴" uptime_hours = int(node_info.get("uptime", 0) / 3600) ascii_parts.append(f""" ┌─ NODE STATUS ────────────────────────────────────────────────────────────────┐ │ Node ID: {node_info.get('node_id', 'unknown')[:16]}... │ │ Status: {status_indicator} {node_info.get('status', 'unknown').upper()} │ │ Uptime: {uptime_hours}h {int((node_info.get('uptime', 0) % 3600) / 60)}m │ │ Version: MY Network {node_info.get('version', '2.0')} │ └──────────────────────────────────────────────────────────────────────────────┘ """) # Информация о пирах peer_count = peers_info.get("peer_count", 0) peer_status = "🌐" if peer_count > 0 else "🏝️" ascii_parts.append(f""" ┌─ NETWORK STATUS ─────────────────────────────────────────────────────────────┐ │ Connected Peers: {peer_status} {peer_count:>3} │ │ Known Nodes: {len(peers_info.get('peers', [])):>3} │ │ Network Health: {'CONNECTED' if peer_count > 0 else 'ISOLATED':>9} │ └──────────────────────────────────────────────────────────────────────────────┘ """) # Статус синхронизации sync_running = sync_status.get("is_running", False) active_syncs = sync_status.get("active_syncs", 0) queue_size = sync_status.get("queue_size", 0) sync_indicator = "⚡" if sync_running else "⏸️" ascii_parts.append(f""" ┌─ SYNC STATUS ────────────────────────────────────────────────────────────────┐ │ Sync Engine: {sync_indicator} {'RUNNING' if sync_running else 'STOPPED':>7} │ │ Active Syncs: {active_syncs:>3} │ │ Queue Size: {queue_size:>3} │ │ Workers: {sync_status.get('workers_count', 0):>3} │ └──────────────────────────────────────────────────────────────────────────────┘ """) # Подвал current_time = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC") ascii_parts.append(f""" ╔══════════════════════════════════════════════════════════════════════════════╗ ║ Last Updated: {current_time} ║ ║ MY Network Protocol - Decentralized Content Distribution System ║ ╚══════════════════════════════════════════════════════════════════════════════╝ """) return "".join(ascii_parts) def generate_offline_ascii() -> str: """Генерировать ASCII для офлайн состояния.""" return """ ╔══════════════════════════════════════════════════════════════════════════════╗ ║ MY NETWORK v2.0 ║ ║ Distributed Content Protocol ║ ╚══════════════════════════════════════════════════════════════════════════════╝ ┌─ SYSTEM STATUS ──────────────────────────────────────────────────────────────┐ │ │ │ 🔴 OFFLINE │ │ │ │ MY Network service is not available │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ ╔══════════════════════════════════════════════════════════════════════════════╗ ║ Status: OFFLINE - Service not initialized ║ ╚══════════════════════════════════════════════════════════════════════════════╝ """ def generate_error_ascii(error_message: str) -> str: """Генерировать ASCII для ошибки.""" return f""" ╔══════════════════════════════════════════════════════════════════════════════╗ ║ MY NETWORK v2.0 ║ ║ Distributed Content Protocol ║ ╚══════════════════════════════════════════════════════════════════════════════╝ ┌─ ERROR STATE ────────────────────────────────────────────────────────────────┐ │ │ │ ❌ ERROR │ │ │ │ {error_message[:64]:^64} │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ ╔══════════════════════════════════════════════════════════════════════════════╗ ║ Status: ERROR - Check system logs for details ║ ╚══════════════════════════════════════════════════════════════════════════════╝ """ def generate_fallback_html(monitoring_data: Dict[str, Any]) -> str: """Генерировать fallback HTML если шаблоны не работают.""" status = monitoring_data.get("status", "unknown") error_message = monitoring_data.get("error", "") # Генерировать информацию о статусе if status == "online": node_info = monitoring_data.get("node_info", {}) peers_info = monitoring_data.get("peers_info", {}) sync_status = monitoring_data.get("sync_status", {}) status_info = f"""
{error_message if error_message else 'MY Network service not available'}
Distributed Content Protocol v2.0
Last Update: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC')}