Add files via upload

This commit is contained in:
Egor
2026-01-17 10:31:40 +03:00
committed by GitHub
parent b7f8469895
commit cd0ce908a1

View File

@@ -0,0 +1,352 @@
"""Schemas for RemnaWave management in cabinet admin panel."""
from datetime import datetime, time
from typing import Any, Dict, List, Literal, Optional
from pydantic import BaseModel, Field
# ============ Status & Connection ============
class ConnectionStatus(BaseModel):
"""RemnaWave API connection status."""
status: str
message: str
api_url: Optional[str] = None
status_code: Optional[int] = None
system_info: Optional[Dict[str, Any]] = None
class RemnaWaveStatusResponse(BaseModel):
"""RemnaWave configuration and connection status."""
is_configured: bool
configuration_error: Optional[str] = None
connection: Optional[ConnectionStatus] = None
# ============ System Statistics ============
class SystemSummary(BaseModel):
"""System summary statistics."""
users_online: int
total_users: int
active_connections: int
nodes_online: int
users_last_day: int
users_last_week: int
users_never_online: int
total_user_traffic: int
class ServerInfo(BaseModel):
"""Server hardware info."""
cpu_cores: int
cpu_physical_cores: int
memory_total: int
memory_used: int
memory_free: int
memory_available: int
uptime_seconds: int
class Bandwidth(BaseModel):
"""Realtime bandwidth statistics."""
realtime_download: int
realtime_upload: int
realtime_total: int
class TrafficPeriod(BaseModel):
"""Traffic statistics for a period."""
current: int
previous: int
difference: Optional[str] = None
class TrafficPeriods(BaseModel):
"""Traffic statistics for multiple periods."""
last_2_days: TrafficPeriod
last_7_days: TrafficPeriod
last_30_days: TrafficPeriod
current_month: TrafficPeriod
current_year: TrafficPeriod
class SystemStatsResponse(BaseModel):
"""Full system statistics response."""
system: SystemSummary
users_by_status: Dict[str, int]
server_info: ServerInfo
bandwidth: Bandwidth
traffic_periods: TrafficPeriods
nodes_realtime: List[Dict[str, Any]] = Field(default_factory=list)
nodes_weekly: List[Dict[str, Any]] = Field(default_factory=list)
last_updated: Optional[datetime] = None
# ============ Nodes ============
class NodeInfo(BaseModel):
"""Node information."""
uuid: str
name: str
address: str
country_code: Optional[str] = None
is_connected: bool
is_disabled: bool
is_node_online: bool
is_xray_running: bool
users_online: Optional[int] = None
traffic_used_bytes: Optional[int] = None
traffic_limit_bytes: Optional[int] = None
last_status_change: Optional[datetime] = None
last_status_message: Optional[str] = None
xray_uptime: Optional[str] = None
is_traffic_tracking_active: bool = False
traffic_reset_day: Optional[int] = None
notify_percent: Optional[int] = None
consumption_multiplier: float = 1.0
cpu_count: Optional[int] = None
cpu_model: Optional[str] = None
total_ram: Optional[str] = None
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
provider_uuid: Optional[str] = None
class NodesListResponse(BaseModel):
"""List of nodes response."""
items: List[NodeInfo]
total: int
class NodesOverview(BaseModel):
"""Nodes overview statistics."""
total: int
online: int
offline: int
disabled: int
total_users_online: int
nodes: List[NodeInfo]
class NodeStatisticsResponse(BaseModel):
"""Node statistics with usage history."""
node: NodeInfo
realtime: Optional[Dict[str, Any]] = None
usage_history: List[Dict[str, Any]] = Field(default_factory=list)
last_updated: Optional[datetime] = None
class NodeUsageResponse(BaseModel):
"""Node usage history response."""
items: List[Dict[str, Any]] = Field(default_factory=list)
class NodeActionRequest(BaseModel):
"""Request to perform node action."""
action: Literal["enable", "disable", "restart"]
class NodeActionResponse(BaseModel):
"""Response after node action."""
success: bool
message: Optional[str] = None
is_disabled: Optional[bool] = None
# ============ Squads (Internal Squads) ============
class SquadInfo(BaseModel):
"""Internal Squad information from RemnaWave."""
uuid: str
name: str
members_count: int
inbounds_count: int
inbounds: List[Dict[str, Any]] = Field(default_factory=list)
class SquadWithLocalInfo(BaseModel):
"""Squad with local database info."""
uuid: str
name: str
members_count: int
inbounds_count: int
inbounds: List[Dict[str, Any]] = Field(default_factory=list)
# Local DB info
local_id: Optional[int] = None
display_name: Optional[str] = None
country_code: Optional[str] = None
is_available: Optional[bool] = None
is_trial_eligible: Optional[bool] = None
price_kopeks: Optional[int] = None
max_users: Optional[int] = None
current_users: Optional[int] = None
is_synced: bool = False
class SquadsListResponse(BaseModel):
"""List of squads response."""
items: List[SquadWithLocalInfo]
total: int
class SquadDetailResponse(BaseModel):
"""Detailed squad response."""
uuid: str
name: str
members_count: int
inbounds_count: int
inbounds: List[Dict[str, Any]] = Field(default_factory=list)
# Local DB info if synced
local_id: Optional[int] = None
display_name: Optional[str] = None
country_code: Optional[str] = None
description: Optional[str] = None
is_available: Optional[bool] = None
is_trial_eligible: Optional[bool] = None
price_kopeks: Optional[int] = None
max_users: Optional[int] = None
current_users: Optional[int] = None
sort_order: Optional[int] = None
is_synced: bool = False
active_subscriptions: int = 0
class SquadCreateRequest(BaseModel):
"""Request to create a new squad."""
name: str = Field(..., min_length=1, max_length=255)
inbound_uuids: List[str] = Field(default_factory=list)
class SquadUpdateRequest(BaseModel):
"""Request to update a squad."""
name: Optional[str] = Field(None, min_length=1, max_length=255)
inbound_uuids: Optional[List[str]] = None
class SquadActionRequest(BaseModel):
"""Request to perform squad action."""
action: Literal["add_all_users", "remove_all_users", "delete", "rename", "update_inbounds"]
name: Optional[str] = None
inbound_uuids: Optional[List[str]] = None
class SquadOperationResponse(BaseModel):
"""Response after squad operation."""
success: bool
message: Optional[str] = None
data: Optional[Dict[str, Any]] = None
# ============ Migration ============
class MigrationPreviewResponse(BaseModel):
"""Preview of squad migration."""
squad_uuid: str
squad_name: str
current_users: int
max_users: Optional[int] = None
users_to_migrate: int
class MigrationRequest(BaseModel):
"""Request to migrate users between squads."""
source_uuid: str
target_uuid: str
class MigrationStats(BaseModel):
"""Migration statistics."""
source_uuid: str
target_uuid: str
total: int = 0
updated: int = 0
panel_updated: int = 0
panel_failed: int = 0
source_removed: int = 0
target_added: int = 0
class MigrationResponse(BaseModel):
"""Response after migration."""
success: bool
message: Optional[str] = None
error: Optional[str] = None
data: Optional[MigrationStats] = None
# ============ Inbounds ============
class InboundInfo(BaseModel):
"""Inbound information."""
uuid: str
tag: str
type: Optional[str] = None
network: Optional[str] = None
security: Optional[str] = None
class InboundsListResponse(BaseModel):
"""List of inbounds response."""
items: List[Dict[str, Any]] = Field(default_factory=list)
total: int = 0
# ============ Auto Sync ============
class AutoSyncTime(BaseModel):
"""Scheduled sync time."""
hour: int
minute: int
class AutoSyncStatus(BaseModel):
"""Auto sync status."""
enabled: bool
times: List[str] = Field(default_factory=list) # HH:MM format
next_run: Optional[datetime] = None
is_running: bool = False
last_run_started_at: Optional[datetime] = None
last_run_finished_at: Optional[datetime] = None
last_run_success: Optional[bool] = None
last_run_reason: Optional[str] = None
last_run_error: Optional[str] = None
last_user_stats: Optional[Dict[str, Any]] = None
last_server_stats: Optional[Dict[str, Any]] = None
class AutoSyncToggleRequest(BaseModel):
"""Request to toggle auto sync."""
enabled: bool
class AutoSyncRunResponse(BaseModel):
"""Response after running sync."""
started: bool
success: Optional[bool] = None
error: Optional[str] = None
user_stats: Optional[Dict[str, Any]] = None
server_stats: Optional[Dict[str, Any]] = None
reason: Optional[str] = None
# ============ Manual Sync ============
class SyncMode(BaseModel):
"""Sync mode options."""
mode: Literal["all", "new_only", "update_only"] = "all"
class SyncResponse(BaseModel):
"""Response after sync operation."""
success: bool
message: Optional[str] = None
data: Optional[Dict[str, Any]] = None
class SyncRecommendations(BaseModel):
"""Sync recommendations."""
success: bool
message: Optional[str] = None
data: Optional[Dict[str, Any]] = None