from __future__ import annotations from dataclasses import dataclass from typing import Any, Dict, List, Literal, Optional # --------------------------- # Models (UI-friendly) # --------------------------- @dataclass(frozen=True) class Status: timestamp: str ip_count: int domain_count: int iface: str table: str mark: str # NOTE: backend uses omitempty for these, so they may be absent. policy_route_ok: Optional[bool] route_ok: Optional[bool] @dataclass(frozen=True) class CmdResult: ok: bool message: str exit_code: Optional[int] = None stdout: str = "" stderr: str = "" @dataclass(frozen=True) class LoginState: state: str email: str msg: str # backend may also provide UI-ready fields text: str color: str @dataclass(frozen=True) class UnitState: state: str @dataclass(frozen=True) class RoutesTimerState: enabled: bool @dataclass(frozen=True) class TrafficModeStatus: mode: str desired_mode: str applied_mode: str preferred_iface: str advanced_active: bool auto_local_bypass: bool auto_local_active: bool ingress_reply_bypass: bool ingress_reply_active: bool bypass_candidates: int force_vpn_subnets: List[str] force_vpn_uids: List[str] force_vpn_cgroups: List[str] force_direct_subnets: List[str] force_direct_uids: List[str] force_direct_cgroups: List[str] overrides_applied: int cgroup_resolved_uids: int cgroup_warning: str active_iface: str iface_reason: str rule_mark: bool rule_full: bool ingress_rule_present: bool ingress_nft_active: bool table_default: bool probe_ok: bool probe_message: str healthy: bool message: str @dataclass(frozen=True) class TrafficInterfaces: interfaces: List[str] preferred_iface: str active_iface: str iface_reason: str @dataclass(frozen=True) class TrafficAppMarksStatus: vpn_count: int direct_count: int message: str @dataclass(frozen=True) class TrafficAppMarksResult: ok: bool message: str op: str = "" target: str = "" cgroup: str = "" cgroup_id: int = 0 timeout_sec: int = 0 @dataclass(frozen=True) class TrafficAppMarkItem: id: int target: str # vpn|direct cgroup: str cgroup_rel: str level: int unit: str command: str app_key: str added_at: str expires_at: str remaining_sec: int @dataclass(frozen=True) class TrafficAppProfile: id: str name: str app_key: str command: str target: str # vpn|direct ttl_sec: int vpn_profile: str created_at: str updated_at: str @dataclass(frozen=True) class TrafficAppProfileSaveResult: ok: bool message: str profile: Optional[TrafficAppProfile] = None @dataclass(frozen=True) class TrafficAudit: ok: bool message: str now: str pretty: str issues: List[str] @dataclass(frozen=True) class TransportClientHealth: last_check: str latency_ms: int last_error: str @dataclass(frozen=True) class TransportClient: id: str name: str kind: str enabled: bool status: str iface: str routing_table: str mark_hex: str priority_base: int capabilities: List[str] health: TransportClientHealth config: Dict[str, Any] updated_at: str @dataclass(frozen=True) class TransportHealthRefreshItem: client_id: str status: str queued: bool reason: str @dataclass(frozen=True) class TransportHealthRefreshResult: ok: bool message: str code: str count: int queued: int skipped: int items: List[TransportHealthRefreshItem] @dataclass(frozen=True) class TransportClientHealthSnapshot: client_id: str status: str latency_ms: int last_error: str last_check: str @dataclass(frozen=True) class TransportPolicyIntent: selector_type: str selector_value: str client_id: str priority: int = 100 mode: str = "strict" @dataclass(frozen=True) class TransportPolicy: revision: int intents: List[TransportPolicyIntent] @dataclass(frozen=True) class TransportConflict: key: str type: str severity: str owners: List[str] reason: str suggested_resolution: str @dataclass(frozen=True) class TransportPolicyValidateSummary: block_count: int warn_count: int @dataclass(frozen=True) class TransportPolicyDiff: added: int changed: int removed: int @dataclass(frozen=True) class TransportPolicyValidateResult: ok: bool message: str code: str valid: bool base_revision: int confirm_token: str summary: TransportPolicyValidateSummary conflicts: List[TransportConflict] diff: TransportPolicyDiff @dataclass(frozen=True) class TransportPolicyApplyResult: ok: bool message: str code: str policy_revision: int current_revision: int apply_id: str rollback_available: bool conflicts: List[TransportConflict] @dataclass(frozen=True) class TransportConflicts: has_blocking: bool items: List[TransportConflict] @dataclass(frozen=True) class TransportCapabilities: clients: Dict[str, Dict[str, bool]] @dataclass(frozen=True) class TransportInterfaceItem: id: str name: str mode: str runtime_iface: str netns_name: str routing_table: str client_ids: List[str] client_count: int up_count: int updated_at: str config: Dict[str, Any] @dataclass(frozen=True) class TransportInterfacesSnapshot: ok: bool message: str code: str count: int items: List[TransportInterfaceItem] @dataclass(frozen=True) class TransportOwnershipRecord: key: str selector_type: str selector_value: str client_id: str client_kind: str owner_scope: str owner_status: str lock_active: bool iface_id: str routing_table: str mark_hex: str priority_base: int mode: str priority: int updated_at: str @dataclass(frozen=True) class TransportOwnershipSnapshot: ok: bool message: str code: str policy_revision: int plan_digest: str count: int lock_count: int items: List[TransportOwnershipRecord] @dataclass(frozen=True) class TransportOwnerLockRecord: destination_ip: str client_id: str client_kind: str iface_id: str mark_hex: str proto: str updated_at: str @dataclass(frozen=True) class TransportOwnerLocksSnapshot: ok: bool message: str code: str policy_revision: int count: int items: List[TransportOwnerLockRecord] @dataclass(frozen=True) class TransportOwnerLocksClearResult: ok: bool message: str code: str base_revision: int confirm_required: bool confirm_token: str match_count: int cleared_count: int remaining_count: int items: List[TransportOwnerLockRecord] @dataclass(frozen=True) class TransportClientActionResult: ok: bool message: str code: str client_id: str kind: str action: str status_before: str status_after: str last_error: str exit_code: Optional[int] = None stdout: str = "" stderr: str = "" @dataclass(frozen=True) class TransportNetnsToggleItem: ok: bool message: str code: str client_id: str kind: str status_before: str status_after: str netns_enabled: bool config_updated: bool provisioned: bool restarted: bool stdout: str = "" stderr: str = "" @dataclass(frozen=True) class TransportNetnsToggleResult: ok: bool message: str code: str enabled: bool count: int success_count: int failure_count: int items: List[TransportNetnsToggleItem] @dataclass(frozen=True) class SingBoxProfileIssue: field: str severity: str code: str message: str @dataclass(frozen=True) class SingBoxProfileRenderDiff: added: int changed: int removed: int @dataclass(frozen=True) class SingBoxProfileValidateResult: ok: bool message: str code: str profile_id: str profile_revision: int valid: bool errors: List[SingBoxProfileIssue] warnings: List[SingBoxProfileIssue] render_digest: str diff: SingBoxProfileRenderDiff @dataclass(frozen=True) class SingBoxProfileApplyResult: ok: bool message: str code: str profile_id: str client_id: str config_path: str profile_revision: int render_revision: int last_applied_at: str render_path: str render_digest: str rollback_available: bool valid: bool errors: List[SingBoxProfileIssue] warnings: List[SingBoxProfileIssue] diff: SingBoxProfileRenderDiff @dataclass(frozen=True) class SingBoxProfile: id: str name: str mode: str protocol: str enabled: bool schema_version: int profile_revision: int render_revision: int last_validated_at: str last_applied_at: str last_error: str typed: Dict[str, Any] raw_config: Dict[str, Any] meta: Dict[str, Any] has_secrets: bool secrets_masked: Dict[str, str] created_at: str updated_at: str @dataclass(frozen=True) class SingBoxProfilesState: ok: bool message: str code: str count: int active_profile_id: str items: List[SingBoxProfile] item: Optional[SingBoxProfile] = None @dataclass(frozen=True) class SingBoxProfileRenderResult: ok: bool message: str code: str profile_id: str profile_revision: int render_revision: int render_path: str render_digest: str changed: bool valid: bool errors: List[SingBoxProfileIssue] warnings: List[SingBoxProfileIssue] diff: SingBoxProfileRenderDiff config: Dict[str, Any] @dataclass(frozen=True) class SingBoxProfileRollbackResult: ok: bool message: str code: str profile_id: str client_id: str config_path: str history_id: str profile_revision: int last_applied_at: str @dataclass(frozen=True) class SingBoxProfileHistoryEntry: id: str at: str profile_id: str action: str status: str code: str message: str profile_revision: int render_revision: int render_digest: str render_path: str client_id: str @dataclass(frozen=True) class SingBoxProfileHistoryResult: ok: bool message: str code: str profile_id: str count: int items: List[SingBoxProfileHistoryEntry] @dataclass(frozen=True) class TrafficCandidateSubnet: cidr: str dev: str kind: str linkdown: bool @dataclass(frozen=True) class TrafficCandidateUnit: unit: str description: str cgroup: str @dataclass(frozen=True) class TrafficCandidateUID: uid: int user: str examples: List[str] @dataclass(frozen=True) class TrafficCandidates: generated_at: str subnets: List[TrafficCandidateSubnet] units: List[TrafficCandidateUnit] uids: List[TrafficCandidateUID] @dataclass(frozen=True) class DnsUpstreams: default1: str default2: str meta1: str meta2: str @dataclass(frozen=True) class DNSBenchmarkUpstream: addr: str enabled: bool = True @dataclass(frozen=True) class DNSBenchmarkResult: upstream: str attempts: int ok: int fail: int nxdomain: int timeout: int temporary: int other: int avg_ms: int p95_ms: int score: float color: str @dataclass(frozen=True) class DNSBenchmarkResponse: results: List[DNSBenchmarkResult] domains_used: List[str] timeout_ms: int attempts_per_domain: int profile: str recommended_default: List[str] recommended_meta: List[str] @dataclass(frozen=True) class DNSUpstreamPoolState: items: List[DNSBenchmarkUpstream] @dataclass(frozen=True) class SmartdnsServiceState: state: str @dataclass(frozen=True) class DNSStatus: via_smartdns: bool smartdns_addr: str mode: str unit_state: str runtime_nftset: bool wildcard_source: str runtime_config_path: str runtime_config_error: str @dataclass(frozen=True) class SmartdnsRuntimeState: enabled: bool applied_enabled: bool wildcard_source: str unit_state: str config_path: str changed: bool = False restarted: bool = False message: str = "" @dataclass(frozen=True) class DomainsTable: lines: List[str] @dataclass(frozen=True) class DomainsFile: name: str content: str source: str = "" @dataclass(frozen=True) class VpnAutoloopStatus: raw_text: str status_word: str @dataclass(frozen=True) class VpnStatus: desired_location: str status_word: str raw_text: str unit_state: str @dataclass(frozen=True) class VpnLocation: label: str iso: str target: str @dataclass(frozen=True) class VpnLocationsState: locations: List[VpnLocation] updated_at: str stale: bool refresh_in_progress: bool last_error: str next_retry_at: str @dataclass(frozen=True) class EgressIdentity: scope: str source: str source_id: str ip: str country_code: str country_name: str updated_at: str stale: bool refresh_in_progress: bool last_error: str next_retry_at: str @dataclass(frozen=True) class EgressIdentityRefreshItem: scope: str status: str queued: bool reason: str @dataclass(frozen=True) class EgressIdentityRefreshResult: ok: bool message: str count: int queued: int skipped: int items: List[EgressIdentityRefreshItem] @dataclass(frozen=True) class TraceDump: lines: List[str] @dataclass(frozen=True) class Event: id: int kind: str ts: str data: Any # --------------------------- # AdGuard VPN interactive login-session (PTY) # --------------------------- @dataclass(frozen=True) class LoginSessionStart: ok: bool phase: str level: str pid: Optional[int] = None email: str = "" error: str = "" @dataclass(frozen=True) class LoginSessionState: ok: bool phase: str level: str alive: bool url: str email: str cursor: int lines: List[str] can_open: bool can_check: bool can_cancel: bool @dataclass(frozen=True) class LoginSessionAction: ok: bool phase: str = "" level: str = "" error: str = "" TraceMode = Literal["full", "gui", "smartdns"] ServiceAction = Literal["start", "stop", "restart"] TransportClientAction = Literal["provision", "start", "stop", "restart"]