118 lines
4.7 KiB
Python
118 lines
4.7 KiB
Python
import asyncio
|
||
import aiomysql
|
||
from dataclasses import dataclass
|
||
from typing import Optional, Tuple
|
||
import time
|
||
|
||
@dataclass
|
||
class ServerStatus:
|
||
auth_online: bool
|
||
world_online: bool
|
||
players_online: int
|
||
max_players: int = 1000
|
||
realm_name: str = "WotLK Server"
|
||
uptime: str = "Unknown"
|
||
|
||
class ServerAPI:
|
||
def __init__(self):
|
||
"""Инициализация API для проверки статуса серверов"""
|
||
# Настройки серверов
|
||
self.auth_address = ('192.168.1.114', 3724)
|
||
self.world_address = ('192.168.1.114', 8085)
|
||
# Настройки БД (только чтение)
|
||
self.db_config = {
|
||
'host': '192.168.1.42',
|
||
'port': 3306,
|
||
'user': 'launcher_ro', # Пользователь для чтения
|
||
'password': 'rPIisIhn46',
|
||
'db': 'acore_characters'
|
||
}
|
||
# Кэш
|
||
self._last_check = None
|
||
self._cache_timeout = 10
|
||
self._players_cache = None
|
||
self._players_cache_time = None
|
||
self._players_cache_timeout = 30
|
||
|
||
async def get_players_count(self) -> int:
|
||
"""Получает количество игроков через БД"""
|
||
try:
|
||
async with aiomysql.connect(**self.db_config) as conn:
|
||
async with conn.cursor() as cur:
|
||
# Запрос согласно структуре БД AzerothCore
|
||
await cur.execute("""
|
||
SELECT COUNT(*) as count
|
||
FROM characters
|
||
WHERE online > 0
|
||
""")
|
||
result = await cur.fetchone()
|
||
count = result[0] if result else 0
|
||
|
||
print(f"Current online players: {count}") # Отладочный вывод
|
||
|
||
# Обновляем кэш
|
||
self._players_cache = count
|
||
self._players_cache_time = time.time()
|
||
|
||
return count
|
||
except Exception as e:
|
||
print(f"Error getting players count: {e}")
|
||
return self._players_cache if self._players_cache is not None else 0
|
||
|
||
async def check_server(self, host: str, port: int) -> bool:
|
||
"""Проверяет доступность сервера"""
|
||
try:
|
||
# Создаем футуру с таймаутом в 2 секунды
|
||
reader, writer = await asyncio.wait_for(
|
||
asyncio.open_connection(host, port),
|
||
timeout=2.0
|
||
)
|
||
writer.close()
|
||
await writer.wait_closed()
|
||
print(f"Server {host}:{port} is online")
|
||
return True
|
||
except (ConnectionRefusedError, asyncio.TimeoutError):
|
||
print(f"Server {host}:{port} is offline")
|
||
return False
|
||
except Exception as e:
|
||
print(f"Error checking server {host}:{port}: {e}")
|
||
return False
|
||
|
||
async def get_server_status(self) -> ServerStatus:
|
||
"""Получает статус серверов"""
|
||
# Проверяем кэш
|
||
if self._last_check:
|
||
if (asyncio.get_event_loop().time() - self._last_check[0]) < self._cache_timeout:
|
||
return self._last_check[1]
|
||
|
||
try:
|
||
# Проверяем оба сервера параллельно
|
||
auth_check, world_check = await asyncio.gather(
|
||
self.check_server(self.auth_address[0], self.auth_address[1]),
|
||
self.check_server(self.world_address[0], self.world_address[1])
|
||
)
|
||
|
||
# Если world сервер онлайн, получаем количество игроков
|
||
players_online = 0
|
||
if world_check:
|
||
try:
|
||
players_online = await self.get_players_count()
|
||
except Exception as e:
|
||
print(f"Error getting players count: {e}")
|
||
|
||
print(f"Status: auth={auth_check}, world={world_check}, players={players_online}")
|
||
status = ServerStatus(
|
||
auth_online=auth_check,
|
||
world_online=world_check,
|
||
players_online=players_online
|
||
)
|
||
# Сохраняем результат в кэш
|
||
self._last_check = (asyncio.get_event_loop().time(), status)
|
||
return status
|
||
except Exception as e:
|
||
print(f"Error in get_server_status: {e}")
|
||
return ServerStatus(
|
||
auth_online=False,
|
||
world_online=False,
|
||
players_online=0
|
||
) |