Remnawave_python-sdk/remnawave/models/bandwidthstats.py
Artem ba1a221593
feat: Update Remnawave SDK to version 2.4.4 with new subscription page management features
- Bump version to 2.4.4 and update description in pyproject.toml
- Refactor RemnawaveSDK to include SubscriptionPageConfigController
- Introduce new subscription page management endpoints:
  - Get, create, update, delete, reorder, and clone subscription page configs
- Remove deprecated NodesUsageHistoryController and UsersStatsController
- Add new bandwidth stats models and endpoints for legacy and new stats
- Enhance tests for bandwidth stats and subscription page management
- Ensure backward compatibility with legacy endpoints while introducing new stats models
2025-12-25 22:30:53 +01:00

294 lines
No EOL
8.1 KiB
Python

from datetime import datetime, date
from typing import List
from uuid import UUID
from pydantic import BaseModel, Field, RootModel
# ============ Legacy Models (Deprecated) ============
class NodeUsageResponseDto(BaseModel):
"""Deprecated: Old node usage model"""
node_uuid: UUID = Field(alias="nodeUuid")
node_name: str = Field(alias="nodeName")
total: int
total_download: float = Field(alias="totalDownload")
total_upload: float = Field(alias="totalUpload")
human_readable_total: str = Field(alias="humanReadableTotal")
human_readable_total_download: str = Field(alias="humanReadableTotalDownload")
human_readable_total_upload: str = Field(alias="humanReadableTotalUpload")
date: date
class NodesUsageResponseDto(RootModel[List[NodeUsageResponseDto]]):
"""Deprecated: Use GetStatsNodesUsageResponseDto instead"""
def __iter__(self):
return iter(self.root)
def __getitem__(self, item):
return self.root[item]
def __bool__(self):
return bool(self.root)
def __len__(self):
return len(self.root)
class GetNodesUsageByRangeResponseDto(RootModel[List[NodeUsageResponseDto]]):
"""Deprecated: Use GetStatsNodesUsageResponseDto instead"""
def __iter__(self):
return iter(self.root)
def __getitem__(self, item):
return self.root[item]
def __bool__(self):
return bool(self.root)
def __len__(self):
return len(self.root)
class NodeRealtimeUsageResponseDto(BaseModel):
"""Deprecated: Use NodeRealtimeUsageItem instead"""
node_uuid: UUID = Field(alias="nodeUuid")
node_name: str = Field(alias="nodeName")
country_code: str = Field(alias="countryCode")
download_bytes: float = Field(alias="downloadBytes")
upload_bytes: float = Field(alias="uploadBytes")
total_bytes: float = Field(alias="totalBytes")
download_speed_bps: float = Field(alias="downloadSpeedBps")
upload_speed_bps: float = Field(alias="uploadSpeedBps")
total_speed_bps: float = Field(alias="totalSpeedBps")
class NodesRealtimeUsageResponseDto(RootModel[List[NodeRealtimeUsageResponseDto]]):
"""Deprecated: Use GetStatsNodesRealtimeUsageResponseDto instead"""
def __iter__(self):
return iter(self.root)
def __getitem__(self, item):
return self.root[item]
def __bool__(self):
return bool(self.root)
def __len__(self):
return len(self.root)
class GetNodesRealtimeUsageResponseDto(RootModel[List[NodeRealtimeUsageResponseDto]]):
"""Deprecated: Use GetStatsNodesRealtimeUsageResponseDto instead"""
def __iter__(self):
return iter(self.root)
def __getitem__(self, item):
return self.root[item]
def __bool__(self):
return bool(self.root)
def __len__(self):
return len(self.root)
class UserUsageByRangeItem(BaseModel):
"""Deprecated: Use LegacyUserUsageItem instead"""
user_uuid: UUID = Field(alias="userUuid")
node_uuid: UUID = Field(alias="nodeUuid")
node_name: str = Field(alias="nodeName")
total: int
date: str
class GetUserUsageByRangeResponseDto(RootModel[List[UserUsageByRangeItem]]):
"""Deprecated: Use GetLegacyStatsUserUsageResponseDto instead"""
def __iter__(self):
return iter(self.root)
def __getitem__(self, item):
return self.root[item]
def __bool__(self):
return bool(self.root)
def __len__(self):
return len(self.root)
class NodeUserUsageItem(BaseModel):
"""Deprecated: Use LegacyNodeUserUsageItem instead"""
user_uuid: UUID = Field(alias="userUuid")
username: str
node_uuid: UUID = Field(alias="nodeUuid")
total: int
date: str
class GetNodeUserUsageByRangeResponseDto(RootModel[List[NodeUserUsageItem]]):
"""Deprecated: Use GetLegacyStatsNodesUsersUsageResponseDto instead"""
def __iter__(self):
return iter(self.root)
def __getitem__(self, item):
return self.root[item]
def __bool__(self):
return bool(self.root)
def __len__(self):
return len(self.root)
# ============ New Stats Models ============
# Legacy Stats Models
class LegacyUserUsageItem(BaseModel):
"""Legacy user usage item"""
user_uuid: UUID = Field(alias="userUuid")
node_uuid: UUID = Field(alias="nodeUuid")
node_name: str = Field(alias="nodeName")
country_code: str = Field(alias="countryCode")
total: int
date: str
class GetLegacyStatsUserUsageResponseDto(RootModel[List[LegacyUserUsageItem]]):
"""Response for legacy user usage"""
@property
def response(self) -> List[LegacyUserUsageItem]:
return self.root
def __iter__(self):
return iter(self.root)
def __getitem__(self, item):
return self.root[item]
class LegacyNodeUserUsageItem(BaseModel):
"""Legacy node user usage item"""
user_uuid: UUID = Field(alias="userUuid")
username: str
node_uuid: UUID = Field(alias="nodeUuid")
total: int
date: str
class GetLegacyStatsNodesUsersUsageResponseDto(RootModel[List[LegacyNodeUserUsageItem]]):
"""Response for legacy nodes users usage"""
@property
def response(self) -> List[LegacyNodeUserUsageItem]:
return self.root
def __iter__(self):
return iter(self.root)
def __getitem__(self, item):
return self.root[item]
# Realtime Stats
class NodeRealtimeUsageItem(BaseModel):
"""Node realtime usage item"""
node_uuid: UUID = Field(alias="nodeUuid")
node_name: str = Field(alias="nodeName")
country_code: str = Field(alias="countryCode")
download_bytes: float = Field(alias="downloadBytes")
upload_bytes: float = Field(alias="uploadBytes")
total_bytes: float = Field(alias="totalBytes")
download_speed_bps: float = Field(alias="downloadSpeedBps")
upload_speed_bps: float = Field(alias="uploadSpeedBps")
total_speed_bps: float = Field(alias="totalSpeedBps")
class GetStatsNodesRealtimeUsageResponseDto(RootModel[List[NodeRealtimeUsageItem]]):
"""Response for nodes realtime usage"""
@property
def response(self) -> List[NodeRealtimeUsageItem]:
return self.root
def __iter__(self):
return iter(self.root)
def __getitem__(self, item):
return self.root[item]
# Stats Nodes Usage (with charts)
class TopNodeItem(BaseModel):
"""Top node item"""
uuid: UUID
color: str
name: str
country_code: str = Field(alias="countryCode")
total: int
class NodeSeriesItem(BaseModel):
"""Node series item for charts"""
uuid: UUID
name: str
color: str
country_code: str = Field(alias="countryCode")
total: int
data: List[int]
class StatsNodesUsageData(BaseModel):
"""Stats nodes usage data"""
categories: List[str]
sparkline_data: List[int] = Field(alias="sparklineData")
top_nodes: List[TopNodeItem] = Field(alias="topNodes")
series: List[NodeSeriesItem]
class GetStatsNodesUsageResponseDto(RootModel[StatsNodesUsageData]):
"""Response for stats nodes usage"""
@property
def response(self) -> StatsNodesUsageData:
return self.root
# Stats Node Users Usage (with charts)
class TopUserItem(BaseModel):
"""Top user item"""
color: str
username: str
total: int
class StatsNodeUsersUsageData(BaseModel):
"""Stats node users usage data"""
categories: List[str]
sparkline_data: List[int] = Field(alias="sparklineData")
top_users: List[TopUserItem] = Field(alias="topUsers")
class GetStatsNodeUsersUsageResponseDto(RootModel[StatsNodeUsersUsageData]):
"""Response for stats node users usage"""
@property
def response(self) -> StatsNodeUsersUsageData:
return self.root
# Stats User Usage (with charts)
class StatsUserUsageData(BaseModel):
"""Stats user usage data"""
categories: List[str]
sparkline_data: List[int] = Field(alias="sparklineData")
top_nodes: List[TopNodeItem] = Field(alias="topNodes")
series: List[NodeSeriesItem]
class GetStatsUserUsageResponseDto(RootModel[StatsUserUsageData]):
"""Response for stats user usage"""
@property
def response(self) -> StatsUserUsageData:
return self.root