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 )