Add terminal session management with heartbeat monitoring, idle timeout detection, session reuse logic, and command history panel UI with search and filtering capabilities
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:
+106
-1
@@ -2,11 +2,55 @@
|
||||
Pydantic schemas for terminal session API.
|
||||
"""
|
||||
from datetime import datetime
|
||||
from typing import Optional, Literal
|
||||
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(
|
||||
@@ -33,16 +77,23 @@ class TerminalSessionResponse(BaseModel):
|
||||
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):
|
||||
@@ -50,3 +101,57 @@ class TerminalSessionList(BaseModel):
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user