Add enhanced terminal history panel UI with animations, keyboard navigation, advanced filtering, search highlighting, and improved storage metrics display with detailed filesystem tables and ZFS/LVM support
Tests / Backend Tests (Python) (3.10) (push) Has been cancelled
Tests / Backend Tests (Python) (3.11) (push) Has been cancelled
Tests / Backend Tests (Python) (3.12) (push) Has been cancelled
Tests / Frontend Tests (JS) (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / All Tests Passed (push) Has been cancelled
Tests / Backend Tests (Python) (3.10) (push) Has been cancelled
Tests / Backend Tests (Python) (3.11) (push) Has been cancelled
Tests / Backend Tests (Python) (3.12) (push) Has been cancelled
Tests / Frontend Tests (JS) (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / All Tests Passed (push) Has been cancelled
This commit is contained in:
@@ -61,12 +61,21 @@ async def get_all_hosts_metrics(
|
||||
"cpu_load_1m": m.cpu_load_1m,
|
||||
"cpu_model": m.cpu_model,
|
||||
"cpu_count": m.cpu_count,
|
||||
"cpu_cores": getattr(m, "cpu_cores", None),
|
||||
"cpu_threads": getattr(m, "cpu_threads", None),
|
||||
"cpu_max_mhz": getattr(m, "cpu_max_mhz", None),
|
||||
"cpu_temperature": getattr(m, "cpu_temperature", None),
|
||||
"memory_usage_percent": m.memory_usage_percent,
|
||||
"memory_total_mb": m.memory_total_mb,
|
||||
"memory_used_mb": m.memory_used_mb,
|
||||
"disk_root_usage_percent": m.disk_root_usage_percent,
|
||||
"disk_root_total_gb": m.disk_root_total_gb,
|
||||
"disk_root_used_gb": m.disk_root_used_gb,
|
||||
"disk_info": getattr(m, "disk_info", None),
|
||||
"disk_devices": getattr(m, "disk_devices", None),
|
||||
"lvm_info": getattr(m, "lvm_info", None),
|
||||
"zfs_info": getattr(m, "zfs_info", None),
|
||||
"storage_details": getattr(m, "storage_details", None),
|
||||
"os_name": m.os_name,
|
||||
"uptime_human": m.uptime_human,
|
||||
"last_collected": collected_at,
|
||||
|
||||
+1620
-557
File diff suppressed because it is too large
Load Diff
+116
-1
@@ -2,9 +2,17 @@
|
||||
Routes WebSocket pour les mises à jour en temps réel.
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, WebSocket, WebSocketDisconnect
|
||||
import asyncio
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Depends, HTTPException, status
|
||||
|
||||
from app.services import ws_manager
|
||||
from app.crud.terminal_session import TerminalSessionRepository
|
||||
from app.services.terminal_service import terminal_service
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@@ -20,3 +28,110 @@ async def websocket_endpoint(websocket: WebSocket):
|
||||
# Traiter les messages entrants si nécessaire
|
||||
except WebSocketDisconnect:
|
||||
ws_manager.disconnect(websocket)
|
||||
|
||||
|
||||
@router.websocket("/terminal/ws/{session_id}")
|
||||
async def terminal_websocket_proxy(
|
||||
websocket: WebSocket,
|
||||
session_id: str,
|
||||
):
|
||||
"""
|
||||
WebSocket proxy for ttyd terminal sessions.
|
||||
|
||||
This endpoint proxies WebSocket connections to the local ttyd instance,
|
||||
allowing the browser to connect through the exposed port 8008 instead of
|
||||
needing direct access to the ttyd port (7680+).
|
||||
|
||||
The session_id is used to look up the ttyd port from the database.
|
||||
Authentication is handled via session token in the query string.
|
||||
"""
|
||||
import socket
|
||||
|
||||
# Get token from query params
|
||||
token = websocket.query_params.get("token")
|
||||
if not token:
|
||||
await websocket.close(code=status.WS_1008_POLICY_VIOLATION, reason="Missing token")
|
||||
return
|
||||
|
||||
# We need a DB session to look up the terminal session
|
||||
# Since we're in a WebSocket endpoint, we need to create one manually
|
||||
from app.core.database import SessionLocal
|
||||
async with SessionLocal() as db_session:
|
||||
session_repo = TerminalSessionRepository(db_session)
|
||||
session = await session_repo.get(session_id)
|
||||
|
||||
if not session:
|
||||
await websocket.close(code=status.WS_1008_POLICY_VIOLATION, reason="Session not found")
|
||||
return
|
||||
|
||||
# Verify token
|
||||
if not terminal_service.verify_token(token, session.token_hash):
|
||||
await websocket.close(code=status.WS_1008_POLICY_VIOLATION, reason="Invalid token")
|
||||
return
|
||||
|
||||
# Accept the WebSocket connection
|
||||
await websocket.accept()
|
||||
|
||||
# Connect to local ttyd via TCP socket
|
||||
ttyd_port = session.ttyd_port
|
||||
ttyd_host = "127.0.0.1" # ttyd is always local in the container
|
||||
|
||||
try:
|
||||
# Create a TCP socket to ttyd
|
||||
reader, writer = await asyncio.open_connection(ttyd_host, ttyd_port)
|
||||
logger.info(f"Proxying WebSocket for session {session_id[:8]}... to ttyd on port {ttyd_port}")
|
||||
|
||||
# Bidirectional proxy: forward messages between WebSocket and ttyd
|
||||
async def forward_ws_to_ttyd():
|
||||
"""Forward WebSocket messages to ttyd."""
|
||||
try:
|
||||
while True:
|
||||
data = await websocket.receive_bytes()
|
||||
writer.write(data)
|
||||
await writer.drain()
|
||||
except WebSocketDisconnect:
|
||||
logger.debug(f"WebSocket disconnected for session {session_id[:8]}...")
|
||||
except Exception as e:
|
||||
logger.error(f"Error forwarding WS to ttyd: {e}")
|
||||
finally:
|
||||
try:
|
||||
writer.close()
|
||||
await writer.wait_closed()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
async def forward_ttyd_to_ws():
|
||||
"""Forward ttyd messages to WebSocket."""
|
||||
try:
|
||||
while True:
|
||||
data = await reader.readexactly(1024)
|
||||
if not data:
|
||||
break
|
||||
await websocket.send_bytes(data)
|
||||
except asyncio.IncompleteReadError:
|
||||
# Normal EOF
|
||||
pass
|
||||
except Exception as e:
|
||||
logger.error(f"Error forwarding ttyd to WS: {e}")
|
||||
finally:
|
||||
try:
|
||||
await websocket.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Run both directions concurrently
|
||||
await asyncio.gather(
|
||||
forward_ws_to_ttyd(),
|
||||
forward_ttyd_to_ws(),
|
||||
return_exceptions=True
|
||||
)
|
||||
|
||||
except ConnectionRefusedError:
|
||||
logger.error(f"Failed to connect to ttyd on {ttyd_host}:{ttyd_port} for session {session_id[:8]}...")
|
||||
await websocket.close(code=1011, reason="ttyd connection failed")
|
||||
except Exception as e:
|
||||
logger.exception(f"Error in terminal WebSocket proxy: {e}")
|
||||
try:
|
||||
await websocket.close(code=1011, reason="Proxy error")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user