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
158 lines
4.0 KiB
Python
158 lines
4.0 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
|
|
created_at: datetime
|
|
host_name: Optional[str] = None
|
|
username: Optional[str] = None
|
|
execution_count: Optional[int] = None
|
|
|
|
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
|
|
|
|
|
|
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
|