Bruno Charest 57bfe02e32
Some checks failed
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
feat: Implement web-based SSH terminal with session management, command logging, and host interaction.
2026-03-03 13:37:52 -05:00

162 lines
4.1 KiB
Python

"""
Pydantic schemas for terminal session API.
"""
from datetime import datetime
from typing import List, Optional, Literal, Any
from pydantic import BaseModel, Field
# ============================================================================
# Command History Schemas
# ============================================================================
class CommandHistoryItem(BaseModel):
"""A single command from history."""
id: int
command: str
command_hash: Optional[str] = None
created_at: datetime
host_id: Optional[str] = None
host_name: Optional[str] = None
username: Optional[str] = None
execution_count: Optional[int] = None
is_pinned: bool = False
class Config:
from_attributes = True
class CommandHistoryResponse(BaseModel):
"""Response containing command history."""
commands: List[CommandHistoryItem]
total: int
host_id: Optional[str] = None
query: Optional[str] = None
class UniqueCommandItem(BaseModel):
"""A unique command with usage stats."""
command: str
command_hash: str
last_used: datetime
execution_count: int
is_pinned: bool = False
class UniqueCommandsResponse(BaseModel):
"""Response containing unique commands."""
commands: List[UniqueCommandItem]
total: int
host_id: str
# ============================================================================
# Terminal Session Schemas
# ============================================================================
class TerminalSessionRequest(BaseModel):
"""Request to create a new terminal session."""
mode: Literal["embedded", "popout"] = Field(
default="embedded",
description="Terminal display mode: embedded in drawer or popout window"
)
class TerminalSessionHost(BaseModel):
"""Host information included in session response."""
id: str
name: str
ip: str
status: str
bootstrap_ok: bool
class TerminalSessionResponse(BaseModel):
"""Response after creating a terminal session."""
session_id: str
url: str
websocket_url: str
expires_at: datetime
ttl_seconds: int
mode: str
host: TerminalSessionHost
reused: bool = False # True if an existing session was reused
token: Optional[str] = None # Only provided for new sessions
class TerminalSessionStatus(BaseModel):
"""Current status of a terminal session."""
session_id: str
status: str
host_id: str
host_name: str
mode: str = "embedded"
created_at: datetime
expires_at: datetime
last_seen_at: Optional[datetime] = None
remaining_seconds: int
age_seconds: int = 0
last_seen_seconds: int = 0
class TerminalSessionList(BaseModel):
"""List of active terminal sessions."""
sessions: list[TerminalSessionStatus]
total: int
max_per_user: int
class ActiveSessionInfo(BaseModel):
"""Info about an active session for limit error response."""
session_id: str
host_id: str
host_name: str
mode: str
age_seconds: int
last_seen_seconds: int
class SessionLimitError(BaseModel):
"""Rich error response when session limit is exceeded."""
error: str = "SESSION_LIMIT"
message: str
max_active: int
current_count: int
active_sessions: List[ActiveSessionInfo]
suggested_actions: List[str]
can_reuse: bool = False
reusable_session_id: Optional[str] = None
class HeartbeatRequest(BaseModel):
"""Request to update session heartbeat."""
pass # Empty body, session_id comes from path
class HeartbeatResponse(BaseModel):
"""Response from heartbeat endpoint."""
session_id: str
status: str
last_seen_at: datetime
remaining_seconds: int
healthy: bool = True
class CloseBeaconRequest(BaseModel):
"""Request from sendBeacon to close session."""
reason: str = "client_close"
class SessionMetrics(BaseModel):
"""Terminal session service metrics."""
sessions_created: int
sessions_reused: int
sessions_closed_user: int
sessions_gc_expired: int
sessions_gc_idle: int
session_limit_hits: int
active_processes: int
allocated_ports: int
gc_running: bool