from datetime import datetime from typing import Any from pydantic import BaseModel, ConfigDict, Field from app.models.service import ServiceEndpointDocument class HealthCheckDocument(BaseModel): model_config = ConfigDict(extra="forbid") enabled: bool = Field(default=True, description="Enable active health checks") protocol: str | None = Field( default=None, description="Override protocol used by the health check", ) path: str = Field(default="/", description="HTTP path to check") method: str = Field(default="GET", description="HTTP method to use") expected_status: int | None = Field( default=None, description="Expected HTTP status code", ) udp_payload: str = Field(default="", description="UDP payload to send") expect_response: bool = Field( default=True, description="Wait for a response when the protocol supports it", ) verify_tls: bool = Field( default=False, description="Verify TLS certificates during health checks", ) benchmark_enabled: bool = Field( default=False, description="Measure response latency during health checks when supported", ) timeout_seconds: float = Field( default=2.0, gt=0, le=30, description="Per-target health check timeout", ) class ProxyDocument(BaseModel): model_config = ConfigDict(extra="forbid") proxy_port: int = Field(..., description="Port exposed by the proxy") name: str = Field(..., description="Human readable proxy name") code: str = Field(..., description="Proxy source or identifier") mode: str = Field(default="reverse", description="mitmproxy proxy mode") mode_spec: str | None = Field( default=None, description="Raw mitmproxy mode specification. Overrides mode/protocol target.", ) protocol: str = Field(default="http", description="mitmproxy reverse protocol") listen_host: str = Field(default="0.0.0.0", description="Proxy listen host") mitm_options: dict[str, Any] = Field( default_factory=dict, description="mitmdump options passed through --set", ) healthcheck: HealthCheckDocument = Field(default_factory=HealthCheckDocument) status: str = Field(default="stopped", description="Runtime proxy status") pid: int | None = Field(default=None, description="mitmdump process id") script_path: str | None = Field(default=None, description="Generated addon path") config_path: str | None = Field(default=None, description="Generated config path") log_path: str | None = Field(default=None, description="mitmdump log path") last_error: str | None = Field(default=None, description="Last runtime error") service: ServiceEndpointDocument = Field( ..., description="Associated upstream service", ) created_at: datetime | None = Field( default=None, description="Creation timestamp in UTC", ) updated_at: datetime | None = Field( default=None, description="Last update timestamp in UTC", ) class ProxyCreateInput(BaseModel): model_config = ConfigDict(extra="forbid") proxy_port: int = Field(..., description="Port exposed by the proxy") name: str = Field(..., description="Human readable proxy name") code: str = Field(..., description="Proxy source or identifier") mode: str = Field(default="reverse", description="mitmproxy proxy mode") mode_spec: str | None = Field( default=None, description="Raw mitmproxy mode specification. Overrides mode/protocol target.", ) protocol: str = Field(default="http", description="mitmproxy reverse protocol") listen_host: str = Field(default="0.0.0.0", description="Proxy listen host") mitm_options: dict[str, Any] = Field(default_factory=dict) healthcheck: HealthCheckDocument = Field(default_factory=HealthCheckDocument) service: ServiceEndpointDocument = Field( ..., description="Associated upstream service", ) class ProxyUpdateInput(BaseModel): model_config = ConfigDict(extra="forbid") name: str | None = Field(default=None, description="Human readable proxy name") code: str | None = Field(default=None, description="Proxy source or identifier") mode: str | None = Field(default=None, description="mitmproxy proxy mode") mode_spec: str | None = Field( default=None, description="Raw mitmproxy mode specification. Overrides mode/protocol target.", ) protocol: str | None = Field(default=None, description="mitmproxy reverse protocol") listen_host: str | None = Field(default=None, description="Proxy listen host") mitm_options: dict[str, Any] | None = Field(default=None) healthcheck: HealthCheckDocument | None = Field(default=None) service: ServiceEndpointDocument | None = Field( default=None, description="Associated upstream service", )