Remnawave_python-sdk/remnawave/controllers/bandwidthstats.py
Artem 294d70e8c6 feat: Обновить SDK до Remnawave API v2.8.0
Новые эндпоинты:
- GET /tokens/scopes (api_tokens_management.get_scopes)
- GET /users/stream — keyset-пагинация (users.get_users_stream)
- PATCH /hosts/bulk/update (hosts_bulk_actions.update_hosts)
- POST /bandwidth-stats/nodes/users (bandwidthstats.get_stats_nodes_users_usage)

Удалённые эндпоинты (вслед за API):
- POST /hosts/bulk/set-inbound, /hosts/bulk/set-port (заменены update_hosts)
- POST /system/tools/happ/encrypt

Изменения моделей:
- Hosts: tags (вместо tag), mihomoIpVersion, pinnedPeerCertSha256,
  verifyPeerCertByName, finalMask, xhttpExtraParams; fingerprint -> str;
  удалены tag/allowInsecure (с обратной совместимостью через свойства)
- API-токены: name/expiresInDays/scopes, tokens/enabled; новый enum Scope
  (полный каталог scope-ов v2.8.0)
- Nodes: nodeConsumptionMultiplier, note, proxyUrl; тело RestartNodeRequestBodyDto
- trafficLimitBytes int -> float (users, nodes, bulk-actions)
- Infra billing: name, nullable nodeUuid, обязательное nextBillingAt
- HWID: requestIp; webhook-события (user/service) обновлены
- Новый enum MihomoIpVersion

Исправления:
- Bulk-ответы хостов переведены на RootModel (раньше падали с ValueError)
- revoke_user_subscription: исправлен порядок Annotated/Optional (тело терялось)
- Restart*RequestBodyDto: populate_by_name (force_restart игнорировался)

Зависимости:
- Убраны избыточные пины pydantic и pydantic-core (покрыты pydantic[email])
- requires-python <3.14 -> <3.15, добавлен классификатор Python 3.14

Версия пакета 2.7.1 -> 2.8.0.
2026-06-30 22:47:15 +02:00

116 lines
No EOL
5.1 KiB
Python

from typing import Annotated
from rapid_api_client import Path, Query
from rapid_api_client.annotations import PydanticBody
from remnawave.models.bandwidthstats import (
GetLegacyStatsNodesUsersUsageResponseDto,
GetLegacyStatsUserUsageResponseDto,
GetNodeUserUsageByRangeResponseDto,
GetNodesRealtimeUsageResponseDto,
GetNodesUsageByRangeResponseDto,
GetStatsNodesRealtimeUsageResponseDto,
GetStatsNodesUsageResponseDto,
GetStatsNodeUsersUsageResponseDto,
GetStatsNodesUsersUsageRequestDto,
GetStatsNodesUsersUsageResponseDto,
GetStatsUserUsageResponseDto,
GetUserUsageByRangeResponseDto,
)
from remnawave.rapid import BaseController, get, post
class BandWidthStatsController(BaseController):
# ============ Legacy Endpoints (Deprecated) ============
@get("/bandwidth-stats/users/{userUuid}/legacy", response_class=GetUserUsageByRangeResponseDto)
async def get_user_usage_legacy_old(
self,
user_uuid: Annotated[str, Path(description="UUID of the user", alias="userUuid")],
start: Annotated[str, Query(description="Start date")],
end: Annotated[str, Query(description="End date")],
) -> GetUserUsageByRangeResponseDto:
"""Get User Usage by Range (Legacy - Deprecated)"""
...
@get("/bandwidth-stats/nodes/{nodeUuid}/users/legacy", response_class=GetNodeUserUsageByRangeResponseDto)
async def get_node_user_usage_legacy_old(
self,
node_uuid: Annotated[str, Path(description="UUID of the node", alias="nodeUuid")],
start: Annotated[str, Query(description="Start date")],
end: Annotated[str, Query(description="End date")],
) -> GetNodeUserUsageByRangeResponseDto:
"""Get Node User Usage by Range and Node UUID (Legacy - Deprecated)"""
...
# ============ New Stats Endpoints ============
@get("/bandwidth-stats/nodes/realtime", response_class=GetStatsNodesRealtimeUsageResponseDto)
async def get_nodes_realtime_usage(
self,
) -> GetStatsNodesRealtimeUsageResponseDto:
"""Get Nodes Realtime Usage"""
...
@get("/bandwidth-stats/nodes/{uuid}/users/legacy", response_class=GetLegacyStatsNodesUsersUsageResponseDto)
async def get_node_users_usage_legacy_stats(
self,
uuid: Annotated[str, Path(description="UUID of the node")],
start: Annotated[str, Query(description="Start date")],
end: Annotated[str, Query(description="End date")],
) -> GetLegacyStatsNodesUsersUsageResponseDto:
"""Get Node Users Usage by Range and Node UUID (Legacy Stats)"""
...
@get("/bandwidth-stats/nodes/{uuid}/users", response_class=GetStatsNodeUsersUsageResponseDto)
async def get_stats_node_users_usage(
self,
uuid: Annotated[str, Path(description="UUID of the node")],
top_users_limit: Annotated[int, Query(description="Limit of top users to return", alias="topUsersLimit")],
start: Annotated[str, Query(description="Start date")],
end: Annotated[str, Query(description="End date")],
) -> GetStatsNodeUsersUsageResponseDto:
"""Get Node Users Usage by Node UUID"""
...
@post("/bandwidth-stats/nodes/users", response_class=GetStatsNodesUsersUsageResponseDto)
async def get_stats_nodes_users_usage(
self,
body: Annotated[GetStatsNodesUsersUsageRequestDto, PydanticBody()],
top_users_limit: Annotated[int, Query(description="Limit of top users to return", alias="topUsersLimit")],
start: Annotated[str, Query(description="Start date (YYYY-MM-DD)")],
end: Annotated[str, Query(description="End date (YYYY-MM-DD)")],
) -> GetStatsNodesUsersUsageResponseDto:
"""Get Nodes Users Usage by Nodes UUIDs"""
...
@get("/bandwidth-stats/users/{uuid}", response_class=GetStatsUserUsageResponseDto)
async def get_stats_user_usage(
self,
uuid: Annotated[str, Path(description="UUID of the user")],
top_nodes_limit: Annotated[int, Query(description="Limit of top nodes to return", alias="topNodesLimit")],
start: Annotated[str, Query(description="Start date")],
end: Annotated[str, Query(description="End date")],
) -> GetStatsUserUsageResponseDto:
"""Get User Usage by Range"""
...
@get("/bandwidth-stats/nodes", response_class=GetStatsNodesUsageResponseDto)
async def get_stats_nodes_usage(
self,
top_nodes_limit: Annotated[int, Query(description="Limit of top nodes to return", alias="topNodesLimit")],
start: Annotated[str, Query(description="Start date")],
end: Annotated[str, Query(description="End date")],
) -> GetStatsNodesUsageResponseDto:
"""Get Nodes Usage by Range"""
...
@get("/bandwidth-stats/users/{uuid}/legacy", response_class=GetLegacyStatsUserUsageResponseDto)
async def get_user_usage_legacy_stats(
self,
uuid: Annotated[str, Path(description="UUID of the user")],
start: Annotated[str, Query(description="Start date")],
end: Annotated[str, Query(description="End date")],
) -> GetLegacyStatsUserUsageResponseDto:
"""Get User Usage by Range (Legacy Stats)"""
...