Files
Solo_bot/web/tblocker.py
T
Capybara-z 5929dc4c8f Add tblocker blocking notifications
- Логика обработчки оповещений на вебхук от tblocker
2025-05-12 22:12:01 +03:00

167 lines
6.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import asyncio
import datetime
from datetime import datetime
import json
import os
import re
import aiohttp
from aiohttp import web
import asyncpg
from aiogram.exceptions import TelegramBadRequest, TelegramForbiddenError, TelegramRetryAfter
from aiogram.types import InlineKeyboardButton
from aiogram.utils.keyboard import InlineKeyboardBuilder
from bot import bot
from config import BLOCK_DURATION, DATABASE_URL, SERVER_COUNTRIES, TIMESTAMP_TTL
from database import get_key_details
from logger import logger
from handlers.buttons import MAIN_MENU
last_unblock_data = {}
def get_country_from_server(server: str) -> str:
"""
Определяет страну сервера по его имени или домену.
Ищет совпадение части домена в полных доменах.
"""
server_part = server.split('.')[0]
for full_domain, country in SERVER_COUNTRIES.items():
if server_part in full_domain:
return country
return server
def handle_telegram_errors(func):
async def wrapper(*args, **kwargs):
try:
return await func(*args, **kwargs)
except TelegramForbiddenError:
tg_id = kwargs.get("tg_id") or args[1]
logger.warning(f"🚫 Бот заблокирован пользователем {tg_id}.")
return False
except TelegramBadRequest:
tg_id = kwargs.get("tg_id") or args[1]
logger.warning(f"🚫 Чат не найден для пользователя {tg_id}.")
return False
except Exception as e:
tg_id = kwargs.get("tg_id") or args[1]
logger.error(f"❌ Ошибка отправки сообщения пользователю {tg_id}: {e}")
return False
return wrapper
@handle_telegram_errors
async def send_notification(tg_id: int, username: str, ip: str, server: str, action: str, timestamp: str):
country = get_country_from_server(server)
builder = InlineKeyboardBuilder()
builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))
if action == 'block':
message = (
f"⚠️ <b>Замечено использование торрентов</b> ⚠️\n\n"
f"<b>Уважаемый пользователь, мы обнаружили использование торрент-трафика в вашей подписке.</b>\n\n"
f"📋 <b>Детали:</b>"
f"<blockquote>"
f"• Подписка: <code>{username}</code>\n"
f"• Сервер: {country}\n"
f"• Время блокировки страны: <b>{BLOCK_DURATION} минут</b>"
f"</blockquote>\n\n"
f"❗️ <b>Важно:</b>\n"
f"• Возможно, вы забыли отключить торрент-клиент и сейчас качаете или раздаете торренты через VPN\n"
f"• Загрузка и раздача через торренты запрещена согласно правилам использования сервиса\n"
f"• Пожалуйста, полностью выключите торрент-клиент\n\n"
f"⏳ <b>После истечения времени блокировки доступ будет автоматически восстановлен.</b>\n\n"
f"⚠️ <b>Внимание:</b> При повторном использовании торрентов, блокировка будет применена снова."
)
else:
message = (
f"✅ <b>Доступ восстановлен</b>\n\n"
f"<b>Уважаемый пользователь, временные ограничения для вашей подписки сняты.</b>\n\n"
f"📋 <b>Детали:</b>"
f"<blockquote>"
f"• Подписка: <code>{username}</code>\n"
f"• Сервер: {country}"
f"</blockquote>\n\n"
f"💬 <b>Напоминание:</b>\n"
f"• Пожалуйста, воздержитесь от использования торрентов\n"
f"• Убедитесь, что торрент-клиент полностью выключен"
)
await bot.send_message(
chat_id=tg_id,
text=message,
parse_mode='HTML',
reply_markup=builder.as_markup()
)
logger.info(f"Отправлено уведомление пользователю {tg_id} о {action} для подписки {username}")
return True
async def tblocker_webhook(request):
try:
data = await request.json()
logger.info(f"Получен запрос от tblocker: {data}")
username = data.get('username')
ip = data.get('ip')
server = data.get('server')
action = data.get('action')
timestamp = data.get('timestamp')
if not all([username, ip, server, action, timestamp]):
logger.error("Неполные данные в вебхуке")
return web.json_response({"error": "Missing required fields"}, status=400)
global last_unblock_data
current_time = datetime.now().timestamp()
last_unblock_data = {
k: v for k, v in last_unblock_data.items()
if current_time - v['received_at'] <= TIMESTAMP_TTL
}
cache_key = f"{username}:{server}"
if action == 'unblock' and cache_key in last_unblock_data:
if timestamp == last_unblock_data[cache_key]['timestamp']:
return web.json_response({"status": "ok", "message": "duplicate unblock skipped"})
if action == 'unblock':
last_unblock_data[cache_key] = {
'timestamp': timestamp,
'received_at': current_time
}
conn = await asyncpg.connect(DATABASE_URL)
try:
key_info = await get_key_details(username, conn)
if not key_info:
logger.error(f"Ключ не найден для email {username}")
return web.json_response({"error": "Key not found"}, status=404)
success = await send_notification(
key_info['tg_id'],
username,
ip,
server,
action,
timestamp
)
if not success:
logger.warning(f"Не удалось отправить уведомление пользователю {key_info['tg_id']}")
return web.json_response({"status": "ok"})
finally:
await conn.close()
except Exception as e:
logger.error(f"Ошибка при обработке вебхука: {str(e)}")
return web.json_response({"error": str(e)}, status=500)