forked from FOSS/ASF-Control-Bot
refactor(asf): use ASF_URL directly, poll restart
This commit is contained in:
+2
-2
@@ -5,5 +5,5 @@ BOT_TOKEN=
|
|||||||
ADMIN_ID=
|
ADMIN_ID=
|
||||||
|
|
||||||
# конфиг ASF
|
# конфиг ASF
|
||||||
ASF_URL="http://127.0.0.1:1242/Api/ASF"
|
ASF_URL=http://127.0.0.1:1242
|
||||||
ASF_PASSWORD="0000"
|
ASF_PASSWORD=0000
|
||||||
|
|||||||
+17
-12
@@ -4,7 +4,6 @@ import requests
|
|||||||
from bot.config import ASF_PASSWORD, ASF_URL
|
from bot.config import ASF_PASSWORD, ASF_URL
|
||||||
from bot.logging_utils import get_logger
|
from bot.logging_utils import get_logger
|
||||||
|
|
||||||
IPC_BASE_URL = "http://127.0.0.1:1242"
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -14,7 +13,7 @@ def _headers() -> dict[str, str | None]:
|
|||||||
|
|
||||||
def asf_get(path: str) -> requests.Response:
|
def asf_get(path: str) -> requests.Response:
|
||||||
logger.info("Отправка GET-запроса в ASF: path=%s", path)
|
logger.info("Отправка GET-запроса в ASF: path=%s", path)
|
||||||
response = requests.get(f"{IPC_BASE_URL}{path}", headers=_headers())
|
response = requests.get(f"{ASF_URL}{path}", headers=_headers())
|
||||||
logger.info(
|
logger.info(
|
||||||
"Получен ответ ASF на GET-запрос: path=%s status=%s",
|
"Получен ответ ASF на GET-запрос: path=%s status=%s",
|
||||||
path,
|
path,
|
||||||
@@ -29,7 +28,7 @@ def asf_post(path: str, payload: dict | None = None) -> requests.Response:
|
|||||||
path,
|
path,
|
||||||
sorted((payload or {}).keys()),
|
sorted((payload or {}).keys()),
|
||||||
)
|
)
|
||||||
response = requests.post(f"{IPC_BASE_URL}{path}", headers=_headers(), json=payload)
|
response = requests.post(f"{ASF_URL}{path}", headers=_headers(), json=payload)
|
||||||
logger.info(
|
logger.info(
|
||||||
"Получен ответ ASF на POST-запрос: path=%s status=%s",
|
"Получен ответ ASF на POST-запрос: path=%s status=%s",
|
||||||
path,
|
path,
|
||||||
@@ -40,7 +39,7 @@ def asf_post(path: str, payload: dict | None = None) -> requests.Response:
|
|||||||
|
|
||||||
def get_asf_status() -> requests.Response:
|
def get_asf_status() -> requests.Response:
|
||||||
logger.info("Запрос статуса ASF")
|
logger.info("Запрос статуса ASF")
|
||||||
response = requests.get(ASF_URL, headers=_headers()) # type: ignore[arg-type]
|
response = requests.get(f"{ASF_URL}/Api/ASF", headers=_headers()) # type: ignore[arg-type]
|
||||||
logger.info("Получен статус ASF: status=%s", response.status_code)
|
logger.info("Получен статус ASF: status=%s", response.status_code)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@@ -74,7 +73,7 @@ async def get_bot_inventory(bot_name: str, appid: int, contextid: int) -> dict |
|
|||||||
)
|
)
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
async with session.get(
|
async with session.get(
|
||||||
f"{IPC_BASE_URL}/Api/Bot/{bot_name}/Inventory/{appid}/{contextid}",
|
f"{ASF_URL}/Api/Bot/{bot_name}/Inventory/{appid}/{contextid}",
|
||||||
headers=_headers(),
|
headers=_headers(),
|
||||||
) as response:
|
) as response:
|
||||||
if response.status != 200:
|
if response.status != 200:
|
||||||
@@ -108,7 +107,7 @@ async def get_2fa_token(bot_name: str) -> str:
|
|||||||
logger.info("Запрос 2FA-кода: bot=%s", bot_name)
|
logger.info("Запрос 2FA-кода: bot=%s", bot_name)
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
async with session.get(
|
async with session.get(
|
||||||
f"{IPC_BASE_URL}/Api/Bot/{bot_name}/TwoFactorAuthentication/Token",
|
f"{ASF_URL}/Api/Bot/{bot_name}/TwoFactorAuthentication/Token",
|
||||||
headers=_headers(),
|
headers=_headers(),
|
||||||
) as response:
|
) as response:
|
||||||
if response.status != 200:
|
if response.status != 200:
|
||||||
@@ -120,13 +119,17 @@ async def get_2fa_token(bot_name: str) -> str:
|
|||||||
return f"Ошибка HTTP {response.status}"
|
return f"Ошибка HTTP {response.status}"
|
||||||
data = await response.json()
|
data = await response.json()
|
||||||
if not data.get("Success"):
|
if not data.get("Success"):
|
||||||
logger.warning("ASF вернул ошибку при запросе 2FA-кода: bot=%s", bot_name)
|
logger.warning(
|
||||||
|
"ASF вернул ошибку при запросе 2FA-кода: bot=%s", bot_name
|
||||||
|
)
|
||||||
return "Ошибка ASF"
|
return "Ошибка ASF"
|
||||||
try:
|
try:
|
||||||
logger.info("2FA-код успешно получен: bot=%s", bot_name)
|
logger.info("2FA-код успешно получен: bot=%s", bot_name)
|
||||||
return data["Result"][bot_name]["Result"]
|
return data["Result"][bot_name]["Result"]
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Не удалось извлечь 2FA-код из ответа ASF: bot=%s", bot_name)
|
logger.exception(
|
||||||
|
"Не удалось извлечь 2FA-код из ответа ASF: bot=%s", bot_name
|
||||||
|
)
|
||||||
return "Не удалось получить код"
|
return "Не удалось получить код"
|
||||||
|
|
||||||
|
|
||||||
@@ -134,7 +137,7 @@ async def get_confirmations(bot_name: str) -> list:
|
|||||||
logger.info("Запрос подтверждений 2FA: bot=%s", bot_name)
|
logger.info("Запрос подтверждений 2FA: bot=%s", bot_name)
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
async with session.get(
|
async with session.get(
|
||||||
f"{IPC_BASE_URL}/Api/Bot/{bot_name}/TwoFactorAuthentication/Confirmations",
|
f"{ASF_URL}/Api/Bot/{bot_name}/TwoFactorAuthentication/Confirmations",
|
||||||
headers=_headers(),
|
headers=_headers(),
|
||||||
) as response:
|
) as response:
|
||||||
if response.status != 200:
|
if response.status != 200:
|
||||||
@@ -171,7 +174,7 @@ async def accept_confirmations(bot_name: str) -> int:
|
|||||||
logger.info("Отправка запроса на подтверждение всех 2FA-операций: bot=%s", bot_name)
|
logger.info("Отправка запроса на подтверждение всех 2FA-операций: bot=%s", bot_name)
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
async with session.post(
|
async with session.post(
|
||||||
f"{IPC_BASE_URL}/Api/Bot/{bot_name}/TwoFactorAuthentication/Confirmations/Accept",
|
f"{ASF_URL}/Api/Bot/{bot_name}/TwoFactorAuthentication/Confirmations/Accept",
|
||||||
headers=_headers(),
|
headers=_headers(),
|
||||||
) as response:
|
) as response:
|
||||||
logger.info(
|
logger.info(
|
||||||
@@ -191,7 +194,7 @@ async def redeem_key(bot_name: str, key: str) -> tuple[bool, str]:
|
|||||||
logger.info("Запрос активации ключа: bot=%s", bot_name)
|
logger.info("Запрос активации ключа: bot=%s", bot_name)
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
async with session.post(
|
async with session.post(
|
||||||
f"{IPC_BASE_URL}/Api/Command",
|
f"{ASF_URL}/Api/Command",
|
||||||
headers=_headers(),
|
headers=_headers(),
|
||||||
json={"Command": f"!redeem {bot_name} {key}"},
|
json={"Command": f"!redeem {bot_name} {key}"},
|
||||||
) as response:
|
) as response:
|
||||||
@@ -204,7 +207,9 @@ async def redeem_key(bot_name: str, key: str) -> tuple[bool, str]:
|
|||||||
return False, f"HTTP_ERROR_{response.status}"
|
return False, f"HTTP_ERROR_{response.status}"
|
||||||
data = await response.json()
|
data = await response.json()
|
||||||
if not data.get("Success"):
|
if not data.get("Success"):
|
||||||
logger.warning("ASF вернул ошибку при активации ключа: bot=%s", bot_name)
|
logger.warning(
|
||||||
|
"ASF вернул ошибку при активации ключа: bot=%s", bot_name
|
||||||
|
)
|
||||||
return False, "ASF_ERROR"
|
return False, "ASF_ERROR"
|
||||||
logger.info("ASF вернул результат активации ключа: bot=%s", bot_name)
|
logger.info("ASF вернул результат активации ключа: bot=%s", bot_name)
|
||||||
return True, str(data.get("Result", ""))
|
return True, str(data.get("Result", ""))
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from bot.state import (
|
|||||||
redeem_messages,
|
redeem_messages,
|
||||||
redeem_users,
|
redeem_users,
|
||||||
)
|
)
|
||||||
from bot.ui.formatters import get_asf_status_text
|
from bot.ui.formatters import get_asf_status_text, get_asf_status
|
||||||
from bot.ui.keyboards import back_keyboard, confirm_action_keyboard, main_keyboard
|
from bot.ui.keyboards import back_keyboard, confirm_action_keyboard, main_keyboard
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
@@ -88,6 +88,7 @@ async def restart_asf(callback: CallbackQuery) -> None:
|
|||||||
await callback.answer()
|
await callback.answer()
|
||||||
try:
|
try:
|
||||||
await callback.message.edit_text("♻ ASF перезапускается...") # type: ignore[union-attr]
|
await callback.message.edit_text("♻ ASF перезапускается...") # type: ignore[union-attr]
|
||||||
|
|
||||||
response = restart_asf_request()
|
response = restart_asf_request()
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
@@ -100,14 +101,28 @@ async def restart_asf(callback: CallbackQuery) -> None:
|
|||||||
reply_markup=main_keyboard(),
|
reply_markup=main_keyboard(),
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
await asyncio.sleep(6)
|
|
||||||
|
# ! Меняется подход к перезапуску ASF: вместо того чтобы ждать
|
||||||
|
# ! 6 секунд, лучше проверять статус ASF до тех пор он не запустится
|
||||||
|
# await asyncio.sleep(6)
|
||||||
|
|
||||||
|
status = get_asf_status()
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
while status.status_code != 200:
|
||||||
|
status = get_asf_status()
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
await callback.message.edit_text( # type: ignore[union-attr]
|
await callback.message.edit_text( # type: ignore[union-attr]
|
||||||
f"ASF успешно перезапущен\n\n{get_asf_status_text()}",
|
f"ASF успешно перезапущен\n\n{get_asf_status_text()}",
|
||||||
reply_markup=main_keyboard(),
|
reply_markup=main_keyboard(),
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info("ASF успешно перезапущен: %s", user)
|
logger.info("ASF успешно перезапущен: %s", user)
|
||||||
|
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.exception("Не удалось перезапустить ASF: %s", user)
|
logger.exception("Не удалось перезапустить ASF: %s", user)
|
||||||
|
|
||||||
await callback.message.edit_text( # type: ignore[union-attr]
|
await callback.message.edit_text( # type: ignore[union-attr]
|
||||||
f"Ошибка: {error}",
|
f"Ошибка: {error}",
|
||||||
reply_markup=main_keyboard(),
|
reply_markup=main_keyboard(),
|
||||||
@@ -123,7 +138,11 @@ async def plugins_handler(callback: CallbackQuery) -> None:
|
|||||||
try:
|
try:
|
||||||
response = get_plugins()
|
response = get_plugins()
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
logger.warning("Не удалось получить список плагинов: %s status=%s", user, response.status_code)
|
logger.warning(
|
||||||
|
"Не удалось получить список плагинов: %s status=%s",
|
||||||
|
user,
|
||||||
|
response.status_code,
|
||||||
|
)
|
||||||
await callback.message.edit_text("Ошибка API") # type: ignore[union-attr]
|
await callback.message.edit_text("Ошибка API") # type: ignore[union-attr]
|
||||||
return
|
return
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|||||||
+27
-8
@@ -68,50 +68,63 @@ def get_uptime(start_time_str: str) -> str:
|
|||||||
|
|
||||||
def format_asf(data: dict) -> str:
|
def format_asf(data: dict) -> str:
|
||||||
result = data.get("Result", {})
|
result = data.get("Result", {})
|
||||||
|
|
||||||
current_version = result.get("Version")
|
current_version = result.get("Version")
|
||||||
latest_version = result.get("LatestVersion", current_version)
|
latest_version = result.get("LatestVersion", current_version)
|
||||||
lines = [f"Версия ASF: {current_version}"]
|
|
||||||
|
lines = [f"Версия ASF: `{current_version}`"]
|
||||||
if current_version != latest_version:
|
if current_version != latest_version:
|
||||||
lines.append(f"Доступно обновление: {latest_version}")
|
lines.append(f"Доступно обновление: `{latest_version}`")
|
||||||
|
|
||||||
memory_kb = result.get("MemoryUsage", 0)
|
memory_kb = result.get("MemoryUsage", 0)
|
||||||
memory_mb = memory_kb / 1024
|
memory_mb = memory_kb / 1024
|
||||||
|
|
||||||
lines.append(f"Используется памяти: {memory_mb:.2f} MB")
|
lines.append(f"Используется памяти: {memory_mb:.2f} MB")
|
||||||
lines.append(f"Работает: {get_uptime(result.get('ProcessStartTime'))}")
|
lines.append(f"Работает: {get_uptime(result.get('ProcessStartTime'))}")
|
||||||
|
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
def get_bot_status_icon(bot: dict) -> str:
|
def get_bot_status_icon(bot: dict) -> str:
|
||||||
online = bot.get("IsConnectedAndLoggedOn", False)
|
online = bot.get("IsConnectedAndLoggedOn", False)
|
||||||
farming = bot.get("CardsFarmer", {}).get("NowFarming", False)
|
farming = bot.get("CardsFarmer", {}).get("NowFarming", False)
|
||||||
|
|
||||||
idle_games = bot.get("BotConfig", {}).get("GamesPlayedWhileIdle", [])
|
idle_games = bot.get("BotConfig", {}).get("GamesPlayedWhileIdle", [])
|
||||||
loaded = bool(bot.get("BotName")) and bool(bot.get("SteamID"))
|
loaded = bool(bot.get("BotName")) and bool(bot.get("SteamID"))
|
||||||
|
|
||||||
if not loaded:
|
if not loaded:
|
||||||
return "🔄"
|
return "🔄"
|
||||||
|
|
||||||
if farming:
|
if farming:
|
||||||
return "🎴"
|
return "🎴"
|
||||||
|
|
||||||
if idle_games and online:
|
if idle_games and online:
|
||||||
return "⌚"
|
return "⌚"
|
||||||
|
|
||||||
if online:
|
if online:
|
||||||
return "🟢"
|
return "🟢"
|
||||||
|
|
||||||
return "🔴"
|
return "🔴"
|
||||||
|
|
||||||
|
|
||||||
def format_bot_ui(bot: dict) -> str:
|
def format_bot_ui(bot: dict) -> str:
|
||||||
online = get_bot_status_icon(bot)
|
online = get_bot_status_icon(bot)
|
||||||
|
|
||||||
now_farming = bot.get("CardsFarmer", {}).get("NowFarming")
|
now_farming = bot.get("CardsFarmer", {}).get("NowFarming")
|
||||||
status_line = (
|
status_line = "🎴 Идет фарм карточек" if now_farming else "🎴 Карточки не фармятся"
|
||||||
"🎴 Идет фарм карточек"
|
|
||||||
if now_farming
|
|
||||||
else "🎴 Карточки не фармятся"
|
|
||||||
)
|
|
||||||
time = bot.get("CardsFarmer", {}).get("TimeRemaining", "00:00:00")
|
time = bot.get("CardsFarmer", {}).get("TimeRemaining", "00:00:00")
|
||||||
games_to_farm = len(bot.get("CardsFarmer", {}).get("GamesToFarm", []))
|
games_to_farm = len(bot.get("CardsFarmer", {}).get("GamesToFarm", []))
|
||||||
|
|
||||||
twofa = "есть" if bot.get("HasMobileAuthenticator") else "нет"
|
twofa = "есть" if bot.get("HasMobileAuthenticator") else "нет"
|
||||||
|
|
||||||
balance = bot.get("WalletBalance", 0) / 100
|
balance = bot.get("WalletBalance", 0) / 100
|
||||||
currency = get_currency_name(bot.get("WalletCurrency", 0))
|
currency = get_currency_name(bot.get("WalletCurrency", 0))
|
||||||
redeem = bot.get("GamesToRedeemInBackgroundCount", 0)
|
|
||||||
steam_id = bot.get("SteamID")
|
steam_id = bot.get("SteamID")
|
||||||
nickname = html.escape(str(bot.get("Nickname") or ""))
|
nickname = html.escape(str(bot.get("Nickname") or ""))
|
||||||
|
redeem = bot.get("GamesToRedeemInBackgroundCount", 0)
|
||||||
|
|
||||||
profile_url = f"https://steamcommunity.com/profiles/{steam_id}"
|
profile_url = f"https://steamcommunity.com/profiles/{steam_id}"
|
||||||
text = (
|
text = (
|
||||||
f"{online} {bot.get('BotName') or 'Загрузка...'}"
|
f"{online} {bot.get('BotName') or 'Загрузка...'}"
|
||||||
@@ -122,6 +135,7 @@ def format_bot_ui(bot: dict) -> str:
|
|||||||
idle_games = bot.get("BotConfig", {}).get("GamesPlayedWhileIdle", [])
|
idle_games = bot.get("BotConfig", {}).get("GamesPlayedWhileIdle", [])
|
||||||
if idle_games:
|
if idle_games:
|
||||||
names = [GAMES.get(game, str(game)) for game in idle_games]
|
names = [GAMES.get(game, str(game)) for game in idle_games]
|
||||||
|
|
||||||
if bot.get("IsConnectedAndLoggedOn"):
|
if bot.get("IsConnectedAndLoggedOn"):
|
||||||
idle_text = f"⌚ Накрутка часов: включена ({', '.join(names)})"
|
idle_text = f"⌚ Накрутка часов: включена ({', '.join(names)})"
|
||||||
else:
|
else:
|
||||||
@@ -130,6 +144,7 @@ def format_bot_ui(bot: dict) -> str:
|
|||||||
"применится после запуска"
|
"применится после запуска"
|
||||||
)
|
)
|
||||||
text += f"{idle_text}\n"
|
text += f"{idle_text}\n"
|
||||||
|
|
||||||
else:
|
else:
|
||||||
text += "⌚ Накрутка часов: выключена\n"
|
text += "⌚ Накрутка часов: выключена\n"
|
||||||
|
|
||||||
@@ -138,6 +153,7 @@ def format_bot_ui(bot: dict) -> str:
|
|||||||
f"🔐 2FA: {twofa}\n\n"
|
f"🔐 2FA: {twofa}\n\n"
|
||||||
f"💰 Баланс: {balance:.2f} {currency}\n"
|
f"💰 Баланс: {balance:.2f} {currency}\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
if redeem > 0:
|
if redeem > 0:
|
||||||
text += f"\nКлючей в очереди: {redeem}\n"
|
text += f"\nКлючей в очереди: {redeem}\n"
|
||||||
if now_farming:
|
if now_farming:
|
||||||
@@ -149,11 +165,14 @@ def format_bot_ui(bot: dict) -> str:
|
|||||||
|
|
||||||
def get_asf_status_text() -> str:
|
def get_asf_status_text() -> str:
|
||||||
response = get_asf_status()
|
response = get_asf_status()
|
||||||
|
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
return f"Ошибка API: {response.status_code}"
|
return f"Ошибка API: {response.status_code}"
|
||||||
|
|
||||||
data = response.json()
|
data = response.json()
|
||||||
if not data.get("Success"):
|
if not data.get("Success"):
|
||||||
return "ASF вернул ошибку"
|
return "ASF вернул ошибку"
|
||||||
|
|
||||||
return f"<b>💻 Панель управления ASF</b>\n\n{format_asf(data)}"
|
return f"<b>💻 Панель управления ASF</b>\n\n{format_asf(data)}"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-6
@@ -10,7 +10,7 @@ def main_keyboard() -> InlineKeyboardMarkup:
|
|||||||
[InlineKeyboardButton(text="🤖 Боты", callback_data="bots")],
|
[InlineKeyboardButton(text="🤖 Боты", callback_data="bots")],
|
||||||
[
|
[
|
||||||
InlineKeyboardButton(
|
InlineKeyboardButton(
|
||||||
text="🔑 Активация ключей на всех аккаунтах",
|
text="🔑 Активация ключей",
|
||||||
callback_data="redeem_keys",
|
callback_data="redeem_keys",
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -35,11 +35,7 @@ def back_keyboard(callback_data: str = "back") -> InlineKeyboardMarkup:
|
|||||||
|
|
||||||
|
|
||||||
def games_keyboard(bot_name: str, is_enabled: bool) -> InlineKeyboardMarkup:
|
def games_keyboard(bot_name: str, is_enabled: bool) -> InlineKeyboardMarkup:
|
||||||
text = (
|
text = "Остановить накрутку CS2" if is_enabled else "⌚ Накрутить часы CS2"
|
||||||
"Остановить накрутку CS2"
|
|
||||||
if is_enabled
|
|
||||||
else "⌚ Накрутить часы CS2"
|
|
||||||
)
|
|
||||||
return InlineKeyboardMarkup(
|
return InlineKeyboardMarkup(
|
||||||
inline_keyboard=[
|
inline_keyboard=[
|
||||||
[InlineKeyboardButton(text=text, callback_data=f"farm|{bot_name}|730")],
|
[InlineKeyboardButton(text=text, callback_data=f"farm|{bot_name}|730")],
|
||||||
|
|||||||
Reference in New Issue
Block a user