mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-01-20 03:40:26 +00:00
1. Traffic (Трафик) - статистика трафика, топ пользователей по трафику, последние нарушения 2. Reports (Отчёты) - отчёты за период (6h, 12h, 24h, 48h, 72h), статистика активных пользователей и IP, топ нарушителей 3. Settings (Настройки) - управление настройками системы банов, группировка по категориям, переключатели для bool, ввод для int 4. Health (Здоровье) - статус системы (healthy/degraded/unhealthy), аптайм, статус компонентов
416 lines
12 KiB
Python
416 lines
12 KiB
Python
"""
|
|
Ban System API Client.
|
|
|
|
Client for interacting with the BedolagaBan monitoring system.
|
|
"""
|
|
import asyncio
|
|
import logging
|
|
from datetime import datetime
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
import aiohttp
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class BanSystemAPIError(Exception):
|
|
"""Ban System API error."""
|
|
|
|
def __init__(self, message: str, status_code: Optional[int] = None, response_data: Optional[dict] = None):
|
|
self.message = message
|
|
self.status_code = status_code
|
|
self.response_data = response_data
|
|
super().__init__(self.message)
|
|
|
|
|
|
class BanSystemAPI:
|
|
"""HTTP client for Ban System API."""
|
|
|
|
def __init__(self, base_url: str, api_token: str, timeout: int = 30):
|
|
self.base_url = base_url.rstrip('/')
|
|
self.api_token = api_token
|
|
self.timeout = aiohttp.ClientTimeout(total=timeout)
|
|
self.session: Optional[aiohttp.ClientSession] = None
|
|
|
|
def _get_headers(self) -> Dict[str, str]:
|
|
"""Get request headers with authorization."""
|
|
return {
|
|
"Authorization": f"Bearer {self.api_token}",
|
|
"Content-Type": "application/json",
|
|
"Accept": "application/json",
|
|
}
|
|
|
|
async def __aenter__(self):
|
|
"""Async context manager entry."""
|
|
self.session = aiohttp.ClientSession(
|
|
timeout=self.timeout,
|
|
headers=self._get_headers()
|
|
)
|
|
return self
|
|
|
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
"""Async context manager exit."""
|
|
if self.session:
|
|
await self.session.close()
|
|
self.session = None
|
|
|
|
async def _ensure_session(self):
|
|
"""Ensure session is created."""
|
|
if self.session is None:
|
|
self.session = aiohttp.ClientSession(
|
|
timeout=self.timeout,
|
|
headers=self._get_headers()
|
|
)
|
|
|
|
async def _request(
|
|
self,
|
|
method: str,
|
|
endpoint: str,
|
|
params: Optional[Dict] = None,
|
|
json_data: Optional[Dict] = None,
|
|
) -> Any:
|
|
"""Execute HTTP request."""
|
|
await self._ensure_session()
|
|
|
|
url = f"{self.base_url}{endpoint}"
|
|
|
|
try:
|
|
async with self.session.request(
|
|
method=method,
|
|
url=url,
|
|
params=params,
|
|
json=json_data,
|
|
) as response:
|
|
response_text = await response.text()
|
|
|
|
if response.status >= 400:
|
|
logger.error(f"Ban System API error: {response.status} - {response_text}")
|
|
raise BanSystemAPIError(
|
|
message=f"API error {response.status}: {response_text}",
|
|
status_code=response.status,
|
|
response_data={"error": response_text}
|
|
)
|
|
|
|
if response_text:
|
|
try:
|
|
return await response.json()
|
|
except Exception:
|
|
return {"raw": response_text}
|
|
return {}
|
|
|
|
except aiohttp.ClientError as e:
|
|
logger.error(f"Ban System API connection error: {e}")
|
|
raise BanSystemAPIError(
|
|
message=f"Connection error: {str(e)}",
|
|
status_code=None,
|
|
response_data=None
|
|
)
|
|
except asyncio.TimeoutError:
|
|
logger.error("Ban System API request timeout")
|
|
raise BanSystemAPIError(
|
|
message="Request timeout",
|
|
status_code=None,
|
|
response_data=None
|
|
)
|
|
|
|
async def close(self):
|
|
"""Close the session."""
|
|
if self.session:
|
|
await self.session.close()
|
|
self.session = None
|
|
|
|
# === Stats ===
|
|
|
|
async def get_stats(self) -> Dict[str, Any]:
|
|
"""
|
|
Get overall system statistics.
|
|
|
|
GET /api/stats
|
|
"""
|
|
return await self._request("GET", "/api/stats")
|
|
|
|
async def get_stats_period(self, hours: int = 24) -> Dict[str, Any]:
|
|
"""
|
|
Get statistics for a specific period.
|
|
|
|
GET /api/stats/period?hours={hours}
|
|
"""
|
|
return await self._request("GET", "/api/stats/period", params={"hours": hours})
|
|
|
|
# === Users ===
|
|
|
|
async def get_users(
|
|
self,
|
|
offset: int = 0,
|
|
limit: int = 50,
|
|
status: Optional[str] = None,
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Get list of users with pagination.
|
|
|
|
GET /api/users
|
|
|
|
Args:
|
|
offset: Pagination offset
|
|
limit: Number of users per page (max 100)
|
|
status: Filter by status (over_limit, with_limit, unlimited)
|
|
"""
|
|
params = {"offset": offset, "limit": min(limit, 100)}
|
|
if status:
|
|
params["status"] = status
|
|
return await self._request("GET", "/api/users", params=params)
|
|
|
|
async def get_users_over_limit(self, limit: int = 50, window: bool = True) -> Dict[str, Any]:
|
|
"""
|
|
Get users who exceeded their device limit.
|
|
|
|
GET /api/users/over-limit
|
|
"""
|
|
return await self._request(
|
|
"GET",
|
|
"/api/users/over-limit",
|
|
params={"limit": limit, "window": str(window).lower()}
|
|
)
|
|
|
|
async def search_users(self, query: str) -> Dict[str, Any]:
|
|
"""
|
|
Search for a user.
|
|
|
|
GET /api/users/search/{query}
|
|
"""
|
|
return await self._request("GET", f"/api/users/search/{query}")
|
|
|
|
async def get_user(self, email: str) -> Dict[str, Any]:
|
|
"""
|
|
Get detailed user information.
|
|
|
|
GET /api/users/{email}
|
|
"""
|
|
return await self._request("GET", f"/api/users/{email}")
|
|
|
|
async def get_user_network(self, email: str) -> Dict[str, Any]:
|
|
"""
|
|
Get user network information (WiFi/Mobile detection).
|
|
|
|
GET /api/users/{email}/network
|
|
"""
|
|
return await self._request("GET", f"/api/users/{email}/network")
|
|
|
|
# === Punishments (Bans) ===
|
|
|
|
async def get_punishments(self) -> List[Dict[str, Any]]:
|
|
"""
|
|
Get list of active punishments (bans).
|
|
|
|
GET /api/punishments
|
|
"""
|
|
return await self._request("GET", "/api/punishments")
|
|
|
|
async def enable_user(self, user_id: str) -> Dict[str, Any]:
|
|
"""
|
|
Enable (unban) a user.
|
|
|
|
POST /api/punishments/{user_id}/enable
|
|
"""
|
|
return await self._request("POST", f"/api/punishments/{user_id}/enable")
|
|
|
|
async def ban_user(
|
|
self,
|
|
username: str,
|
|
minutes: int = 30,
|
|
reason: Optional[str] = None,
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Manually ban a user.
|
|
|
|
POST /api/ban
|
|
"""
|
|
params = {"username": username, "minutes": minutes}
|
|
if reason:
|
|
params["reason"] = reason
|
|
return await self._request("POST", "/api/ban", params=params)
|
|
|
|
async def get_punishment_history(self, query: str, limit: int = 20) -> List[Dict[str, Any]]:
|
|
"""
|
|
Get punishment history for a user.
|
|
|
|
GET /api/history/{query}
|
|
"""
|
|
return await self._request(
|
|
"GET",
|
|
f"/api/history/{query}",
|
|
params={"limit": limit}
|
|
)
|
|
|
|
# === Nodes ===
|
|
|
|
async def get_nodes(self, include_agent_stats: bool = True) -> List[Dict[str, Any]]:
|
|
"""
|
|
Get list of connected nodes.
|
|
|
|
GET /api/nodes
|
|
"""
|
|
return await self._request(
|
|
"GET",
|
|
"/api/nodes",
|
|
params={"include_agent_stats": str(include_agent_stats).lower()}
|
|
)
|
|
|
|
# === Agents ===
|
|
|
|
async def get_agents(
|
|
self,
|
|
search: Optional[str] = None,
|
|
health: Optional[str] = None,
|
|
status: Optional[str] = None,
|
|
sort_by: str = "name",
|
|
sort_order: str = "asc",
|
|
) -> Dict[str, Any]:
|
|
"""
|
|
Get list of monitoring agents.
|
|
|
|
GET /api/agents
|
|
|
|
Args:
|
|
search: Search query
|
|
health: Filter by health (healthy, warning, critical)
|
|
status: Filter by status (online, offline)
|
|
sort_by: Sort by field (name, sent, dropped, health)
|
|
sort_order: Sort order (asc, desc)
|
|
"""
|
|
params = {"sort_by": sort_by, "sort_order": sort_order}
|
|
if search:
|
|
params["search"] = search
|
|
if health:
|
|
params["health"] = health
|
|
if status:
|
|
params["status"] = status
|
|
return await self._request("GET", "/api/agents", params=params)
|
|
|
|
async def get_agents_summary(self) -> Dict[str, Any]:
|
|
"""
|
|
Get summary statistics for all agents.
|
|
|
|
GET /api/agents/summary
|
|
"""
|
|
return await self._request("GET", "/api/agents/summary")
|
|
|
|
async def get_agent_history(
|
|
self,
|
|
node_name: str,
|
|
hours: int = 24,
|
|
limit: int = 50,
|
|
) -> List[Dict[str, Any]]:
|
|
"""
|
|
Get agent statistics history.
|
|
|
|
GET /api/agents/{node_name}/history
|
|
"""
|
|
return await self._request(
|
|
"GET",
|
|
f"/api/agents/{node_name}/history",
|
|
params={"hours": hours, "limit": limit}
|
|
)
|
|
|
|
# === Traffic ===
|
|
|
|
async def get_traffic(self) -> Dict[str, Any]:
|
|
"""
|
|
Get overall traffic statistics.
|
|
|
|
GET /api/traffic
|
|
"""
|
|
return await self._request("GET", "/api/traffic")
|
|
|
|
async def get_traffic_top(self, limit: int = 20) -> List[Dict[str, Any]]:
|
|
"""
|
|
Get top users by traffic.
|
|
|
|
GET /api/traffic/top
|
|
"""
|
|
return await self._request("GET", "/api/traffic/top", params={"limit": limit})
|
|
|
|
async def get_user_traffic(self, username: str) -> Dict[str, Any]:
|
|
"""
|
|
Get traffic information for a specific user.
|
|
|
|
GET /api/traffic/user/{username}
|
|
"""
|
|
return await self._request("GET", f"/api/traffic/user/{username}")
|
|
|
|
async def get_traffic_violations(self, limit: int = 50) -> List[Dict[str, Any]]:
|
|
"""
|
|
Get list of traffic limit violations.
|
|
|
|
GET /api/traffic/violations
|
|
"""
|
|
return await self._request("GET", "/api/traffic/violations", params={"limit": limit})
|
|
|
|
# === Health ===
|
|
|
|
async def health_check(self) -> Dict[str, Any]:
|
|
"""
|
|
Check API health.
|
|
|
|
GET /health
|
|
"""
|
|
return await self._request("GET", "/health")
|
|
|
|
async def health_detailed(self) -> Dict[str, Any]:
|
|
"""
|
|
Get detailed health information.
|
|
|
|
GET /health/detailed
|
|
"""
|
|
return await self._request("GET", "/health/detailed")
|
|
|
|
# === Settings ===
|
|
|
|
async def get_settings(self) -> Dict[str, Any]:
|
|
"""
|
|
Get all settings with their definitions.
|
|
|
|
GET /api/settings
|
|
"""
|
|
return await self._request("GET", "/api/settings")
|
|
|
|
async def get_setting(self, key: str) -> Dict[str, Any]:
|
|
"""
|
|
Get a specific setting value.
|
|
|
|
GET /api/settings/{key}
|
|
"""
|
|
return await self._request("GET", f"/api/settings/{key}")
|
|
|
|
async def set_setting(self, key: str, value: Any) -> Dict[str, Any]:
|
|
"""
|
|
Set a setting value.
|
|
|
|
POST /api/settings/{key}?value={value}
|
|
"""
|
|
return await self._request("POST", f"/api/settings/{key}", params={"value": value})
|
|
|
|
async def toggle_setting(self, key: str) -> Dict[str, Any]:
|
|
"""
|
|
Toggle a boolean setting.
|
|
|
|
POST /api/settings/{key}/toggle
|
|
"""
|
|
return await self._request("POST", f"/api/settings/{key}/toggle")
|
|
|
|
async def whitelist_add(self, username: str) -> Dict[str, Any]:
|
|
"""
|
|
Add user to whitelist.
|
|
|
|
POST /api/settings/whitelist/add?username={username}
|
|
"""
|
|
return await self._request("POST", "/api/settings/whitelist/add", params={"username": username})
|
|
|
|
async def whitelist_remove(self, username: str) -> Dict[str, Any]:
|
|
"""
|
|
Remove user from whitelist.
|
|
|
|
POST /api/settings/whitelist/remove?username={username}
|
|
"""
|
|
return await self._request("POST", "/api/settings/whitelist/remove", params={"username": username})
|