from __future__ import annotations from pathlib import Path from typing import Literal from pydantic import BaseModel, Field class ConfSource(BaseModel): key: str source_type: Literal["url", "file", "inline", "base64"] = "url" value: str enabled: bool = True cache_ttl: int | None = None options: dict[str, str] = Field(default_factory=dict) line_no: int class ConfSelector(BaseModel): key: str regex: str line_no: int class ConfGroup(BaseModel): name: str group_type: str tokens: list[str] = Field(default_factory=list) raw: str line_no: int class ConfModule(BaseModel): key: str path: str policy: str order: int enabled: bool = True line_no: int def resolved_path(self, config_dir: Path) -> Path: return (config_dir / self.path).resolve() class ConfBuiltin(BaseModel): key: str builtin_type: Literal["GEOIP", "FINAL"] value: str = "" policy: str order: int enabled: bool = True line_no: int class ConfBaseConfig(BaseModel): listen: str | None = None output_dir: str | None = None cache_dir: str | None = None mode: str | None = None allow_lan: bool | None = None log_level: str | None = None ipv6: bool | None = None append_userinfo_header: bool | None = None userinfo_source_policy: str | None = None sources: list[ConfSource] = Field(default_factory=list) selectors: list[ConfSelector] = Field(default_factory=list) groups: list[ConfGroup] = Field(default_factory=list) modules: list[ConfModule] = Field(default_factory=list) builtins: list[ConfBuiltin] = Field(default_factory=list)