Files
ProxMenux/AppImage/scripts/flask_server.py

179 lines
6.6 KiB
Python
Raw Normal View History

2025-09-28 19:40:23 +02:00
#!/usr/bin/env python3
"""
2026-01-29 17:47:10 +01:00
ProxMenux Flask Server (Entry Point)
2025-11-21 18:32:10 +01:00
2026-01-29 17:47:10 +01:00
Este script es el punto de entrada principal. Su función es:
1. Inicializar la aplicación Flask.
2. Configurar CORS.
3. Registrar todos los módulos (Blueprints) que hemos separado.
4. Servir la interfaz web (Frontend).
2025-09-28 19:40:23 +02:00
"""
import os
2025-11-04 21:27:29 +01:00
import sys
2026-01-29 17:47:10 +01:00
import logging
from flask import Flask, jsonify, send_file, send_from_directory
2025-11-21 18:32:10 +01:00
from flask_cors import CORS
2026-01-29 17:47:10 +01:00
# --- Importar Blueprints Existentes (Los que ya tenías y no hemos tocado) ---
from flask_auth_routes import auth_bp
from flask_health_routes import health_bp
from flask_proxmenux_routes import proxmenux_bp
from flask_terminal_routes import terminal_bp, init_terminal_routes
# --- Importar Nuevos Blueprints (Los 5 módulos que acabas de crear) ---
# Asegúrate de que los archivos .py se llamen exactamente así para que funcionen los imports:
from flask_system_routes import system_bp
from flask_storage_routes import storage_bp
from flask_network_routes import network_bp
from flask_vm_routes import vm_bp
from flask_hardware_routes import hardware_bp
from flask_script_routes import script_bp
# Configuración de Logging
2025-11-21 18:32:10 +01:00
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
)
2026-01-29 17:47:10 +01:00
logger = logging.getLogger("proxmenux.server")
2025-11-18 18:33:57 +01:00
2026-01-29 17:47:10 +01:00
# Inicializar Flask
app = Flask(__name__)
CORS(app) # Habilitar CORS para permitir peticiones desde el frontend
2025-11-04 21:02:56 +01:00
2025-11-21 18:32:10 +01:00
# -------------------------------------------------------------------
2026-01-29 17:47:10 +01:00
# Registro de Módulos (Blueprints)
# Aquí es donde "conectamos" todos los archivos separados a la app principal
2025-11-21 18:32:10 +01:00
# -------------------------------------------------------------------
2025-11-04 11:03:09 +01:00
2026-01-29 17:47:10 +01:00
# 1. Módulos de Utilidad y Autenticación
2025-11-04 21:02:56 +01:00
app.register_blueprint(auth_bp)
2025-11-04 22:28:42 +01:00
app.register_blueprint(health_bp)
2025-11-09 20:52:39 +01:00
app.register_blueprint(proxmenux_bp)
2026-01-29 17:47:10 +01:00
app.register_blueprint(terminal_bp)
2025-11-04 09:46:11 +01:00
2026-01-29 17:47:10 +01:00
# 2. Módulos Principales de Monitorización (Nuevos)
app.register_blueprint(system_bp) # Rutas: /api/system, /api/logs, /api/events
app.register_blueprint(storage_bp) # Rutas: /api/storage, /api/backups
app.register_blueprint(network_bp) # Rutas: /api/network
app.register_blueprint(vm_bp) # Rutas: /api/vms
app.register_blueprint(hardware_bp) # Rutas: /api/hardware, /api/gpu
app.register_blueprint(script_bp) # Rutas: /api/scripts
2025-10-04 19:25:28 +02:00
2026-01-29 17:47:10 +01:00
# Inicializar WebSocket para la terminal y ejecución de scripts
init_terminal_routes(app)
2025-10-27 00:03:26 +01:00
2026-01-29 17:47:10 +01:00
# -------------------------------------------------------------------
# Rutas del Frontend (Servir Dashboard Next.js estático)
# -------------------------------------------------------------------
2025-10-04 19:25:28 +02:00
2025-09-28 19:40:23 +02:00
@app.route('/')
def serve_dashboard():
2026-01-29 17:47:10 +01:00
"""Sirve la página principal (index.html) del dashboard."""
2025-09-28 19:40:23 +02:00
try:
2026-01-29 17:47:10 +01:00
# Detectar la raíz del AppImage o directorio actual
2025-09-29 19:19:35 +02:00
appimage_root = os.environ.get('APPDIR')
if not appimage_root:
2026-01-29 17:47:10 +01:00
# Fallback para desarrollo: detectar ruta relativa
2025-09-29 19:19:35 +02:00
base_dir = os.path.dirname(os.path.abspath(__file__))
2025-10-05 22:40:38 +02:00
if base_dir.endswith('usr/bin'):
appimage_root = os.path.dirname(os.path.dirname(base_dir))
else:
appimage_root = os.path.dirname(base_dir)
2025-10-06 11:02:00 +02:00
index_path = os.path.join(appimage_root, 'web', 'index.html')
2025-09-28 19:40:23 +02:00
2026-01-29 17:47:10 +01:00
if os.path.exists(index_path):
return send_file(index_path)
2025-09-29 18:07:30 +02:00
2026-01-29 17:47:10 +01:00
# Si no encuentra el dashboard, mostrar mensaje de error útil en el navegador
return f"""
<html><body style="background:#111;color:#eee;font-family:sans-serif;padding:2rem;">
<h1>ProxMenux Monitor</h1>
<p>Dashboard not found at: {index_path}</p>
<p>The API is running correctly. Check your AppImage build structure.</p>
</body></html>
""", 404
2025-09-29 18:07:30 +02:00
except Exception as e:
2026-01-29 17:47:10 +01:00
return jsonify({'error': f'Dashboard error: {str(e)}'}), 500
2025-09-28 19:40:23 +02:00
2025-09-29 18:07:30 +02:00
@app.route('/_next/<path:filename>')
def serve_next_static(filename):
2026-01-29 17:47:10 +01:00
"""Sirve archivos estáticos de Next.js (_next/static/...)."""
2025-09-29 18:07:30 +02:00
try:
2025-09-29 19:19:35 +02:00
appimage_root = os.environ.get('APPDIR')
if not appimage_root:
base_dir = os.path.dirname(os.path.abspath(__file__))
2025-10-05 22:40:38 +02:00
if base_dir.endswith('usr/bin'):
appimage_root = os.path.dirname(os.path.dirname(base_dir))
else:
appimage_root = os.path.dirname(base_dir)
2026-01-29 17:47:10 +01:00
2025-10-06 11:02:00 +02:00
static_dir = os.path.join(appimage_root, 'web', '_next')
2026-01-29 17:47:10 +01:00
return send_from_directory(static_dir, filename)
except Exception:
2025-09-29 18:07:30 +02:00
return '', 404
2026-01-29 17:47:10 +01:00
@app.route('/images/<path:filename>')
def serve_images(filename):
"""Sirve imágenes estáticas."""
2025-09-28 19:40:23 +02:00
try:
2025-09-29 19:19:35 +02:00
appimage_root = os.environ.get('APPDIR')
if not appimage_root:
base_dir = os.path.dirname(os.path.abspath(__file__))
2025-10-05 22:40:38 +02:00
if base_dir.endswith('usr/bin'):
appimage_root = os.path.dirname(os.path.dirname(base_dir))
else:
appimage_root = os.path.dirname(base_dir)
2026-01-29 17:47:10 +01:00
image_dir = os.path.join(appimage_root, 'web', 'images')
return send_from_directory(image_dir, filename)
except Exception:
2025-09-28 19:40:23 +02:00
return '', 404
2026-01-29 17:47:10 +01:00
@app.route('/<path:filename>')
def serve_static_files(filename):
"""Sirve archivos raíz (favicon, manifest, etc.)."""
2025-09-28 19:40:23 +02:00
try:
2025-10-01 17:10:37 +02:00
appimage_root = os.environ.get('APPDIR')
if not appimage_root:
base_dir = os.path.dirname(os.path.abspath(__file__))
2025-10-05 22:40:38 +02:00
if base_dir.endswith('usr/bin'):
appimage_root = os.path.dirname(os.path.dirname(base_dir))
else:
appimage_root = os.path.dirname(base_dir)
2025-11-04 15:09:23 +01:00
2026-01-29 17:47:10 +01:00
web_dir = os.path.join(appimage_root, 'web')
return send_from_directory(web_dir, filename)
except Exception:
return '', 404
2025-10-26 23:58:02 +01:00
2026-01-29 17:47:10 +01:00
@app.route('/api/info', methods=['GET'])
def api_info():
"""Endpoint raíz de la API para verificar funcionamiento y listar endpoints disponibles."""
return jsonify({
'name': 'ProxMenux Monitor API',
'version': '1.0.3 (Modular)',
'status': 'online',
'endpoints': [
'/api/system',
'/api/storage',
'/api/network',
'/api/vms',
'/api/hardware',
'/api/gpu/realtime'
2025-10-04 17:34:07 +02:00
]
2026-01-29 17:47:10 +01:00
})
2025-10-04 17:48:10 +02:00
2026-01-29 17:47:10 +01:00
if __name__ == '__main__':
# Silenciar banner de Flask CLI para mantener logs limpios en la consola
import sys
2025-10-26 22:11:02 +01:00
try:
2026-01-29 17:47:10 +01:00
cli = sys.modules['flask.cli']
cli.show_server_banner = lambda *x: None
except: pass
2025-10-25 23:39:23 +02:00
2026-01-29 17:47:10 +01:00
# Iniciar servidor en el puerto 8008
print("🚀 ProxMenux Monitor API (Modular) running on port 8008...")
app.run(host='0.0.0.0', port=8008, debug=False)