diff --git a/handlers/keys/key_mode/key_cluster_mode.py b/handlers/keys/key_mode/key_cluster_mode.py index b6ac41d9..dbc4039a 100644 --- a/handlers/keys/key_mode/key_cluster_mode.py +++ b/handlers/keys/key_mode/key_cluster_mode.py @@ -84,8 +84,11 @@ async def key_cluster_mode( traffic_limit_bytes = int(TRIAL_CONFIG.get("traffic_limit_gb", 100) * 1024**3) elif plan: tariff = await get_tariff_by_id(session, plan) - if tariff and tariff.get("device_limit") is not None: - device_limit = int(tariff["device_limit"]) + if tariff: + if tariff.get("device_limit") is not None: + device_limit = int(tariff["device_limit"]) + if tariff.get("traffic_limit_gb") is not None: + traffic_limit_bytes = int(tariff["traffic_limit_gb"] * 1024**3) least_loaded_cluster = await get_least_loaded_cluster(session) await create_key_on_cluster( @@ -98,6 +101,7 @@ async def key_cluster_mode( session=session, hwid_limit=device_limit, traffic_limit_bytes=traffic_limit_bytes, + is_trial=is_trial, ) logger.info( diff --git a/handlers/keys/key_mode/key_country_mode.py b/handlers/keys/key_mode/key_country_mode.py index 99d410ff..f145b17b 100644 --- a/handlers/keys/key_mode/key_country_mode.py +++ b/handlers/keys/key_mode/key_country_mode.py @@ -41,6 +41,7 @@ from handlers.buttons import ( PC_BUTTON, SUPPORT, TV_BUTTON, + MY_SUB ) from handlers.keys.key_utils import create_client_on_server from handlers.texts import SELECT_COUNTRY_MSG, key_message_success @@ -349,7 +350,6 @@ async def finalize_key_creation( client_id = old_key_details["client_id"] email = old_key_details["email"] expiry_timestamp = old_key_details["expiry_time"] - else: while True: key_name = generate_random_email() @@ -360,6 +360,25 @@ async def finalize_key_creation( email = key_name.lower() expiry_timestamp = int(expiry_time.timestamp() * 1000) + traffic_limit_bytes = None + device_limit = 0 + data = await state.get_data() if state else {} + is_trial = data.get("is_trial", False) + + if is_trial: + from config import TRIAL_CONFIG + traffic_limit_bytes = int(TRIAL_CONFIG.get("traffic_limit_gb", 100)) * 1024**3 + device_limit = TRIAL_CONFIG.get("hwid_limit", 1) + elif data.get("tariff_id") or tariff_id: + tariff_id = data.get("tariff_id") or tariff_id + result = await session.execute(select(Tariff).where(Tariff.id == tariff_id)) + tariff = result.scalar_one_or_none() + if tariff: + if tariff.traffic_limit is not None: + traffic_limit_bytes = int(tariff.traffic_limit) + if tariff.device_limit is not None: + device_limit = int(tariff.device_limit) + public_link = None remnawave_link = None created_at = int(datetime.now(moscow_tz).timestamp() * 1000) @@ -373,31 +392,22 @@ async def finalize_key_creation( raise ValueError(f"Сервер {selected_country} не найден") panel_type = server_info.panel_type.lower() - cluster_info = await check_server_name_by_cluster( - session, server_info.server_name - ) + cluster_info = await check_server_name_by_cluster(session, server_info.server_name) if not cluster_info: raise ValueError(f"Кластер для сервера {server_info.server_name} не найден") - is_full_remnawave = await is_full_remnawave_cluster( - cluster_info["cluster_name"], session - ) + is_full_remnawave = await is_full_remnawave_cluster(cluster_info["cluster_name"], session) if old_key_name: old_server_id = old_key_details["server_id"] if old_server_id: - result = await session.execute( - select(Server).where(Server.server_name == old_server_id) - ) + result = await session.execute(select(Server).where(Server.server_name == old_server_id)) old_server_info = result.scalar_one_or_none() if old_server_info: try: if old_server_info.panel_type.lower() == "3x-ui": xui = await get_xui_instance(old_server_info.api_url) - await delete_client( - xui, old_server_info.inbound_id, email, client_id - ) - + await delete_client(xui, old_server_info.inbound_id, email, client_id) await session.execute( update(Key) .where(Key.tg_id == tg_id, Key.email == email) @@ -418,21 +428,21 @@ async def finalize_key_creation( if panel_type == "remnawave" or is_full_remnawave: remna = RemnawaveAPI(server_info.api_url) if not await remna.login(REMNAWAVE_LOGIN, REMNAWAVE_PASSWORD): - raise ValueError( - f"❌ Не удалось авторизоваться в Remnawave ({server_info.server_name})" - ) + raise ValueError(f"❌ Не удалось авторизоваться в Remnawave ({server_info.server_name})") - expire_at = ( - datetime.utcfromtimestamp(expiry_timestamp / 1000).isoformat() + "Z" - ) + expire_at = datetime.utcfromtimestamp(expiry_timestamp / 1000).isoformat() + "Z" user_data = { "username": email, "trafficLimitStrategy": "NO_RESET", "expireAt": expire_at, "telegramId": tg_id, "activeUserInbounds": [server_info.inbound_id], - "hwidDeviceLimit": 0, } + if traffic_limit_bytes: + user_data["trafficLimitBytes"] = traffic_limit_bytes + if device_limit: + user_data["hwidDeviceLimit"] = device_limit + result = await remna.create_user(user_data) if not result: raise ValueError("❌ Ошибка при создании пользователя в Remnawave") @@ -442,9 +452,7 @@ async def finalize_key_creation( if old_key_name: await session.execute( - update(Key) - .where(Key.tg_id == tg_id, Key.email == email) - .values(client_id=client_id) + update(Key).where(Key.tg_id == tg_id, Key.email == email).values(client_id=client_id) ) if panel_type == "3x-ui": @@ -461,12 +469,13 @@ async def finalize_key_creation( email=email, expiry_timestamp=expiry_timestamp, semaphore=semaphore, + session=session, + plan=tariff_id, + is_trial=is_trial, ) public_link = f"{PUBLIC_LINK}{email}/{tg_id}" - logger.info( - f"[Key Creation] Подписка создана для пользователя {tg_id} на сервере {selected_country}" - ) + logger.info(f"[Key Creation] Подписка создана для пользователя {tg_id} на сервере {selected_country}") if old_key_name: update_data = {"server_id": selected_country} @@ -474,19 +483,8 @@ async def finalize_key_creation( update_data["key"] = public_link elif panel_type == "remnawave": update_data["remnawave_link"] = remnawave_link - - await session.execute( - update(Key) - .where(Key.tg_id == tg_id, Key.email == email) - .values(**update_data) - ) + await session.execute(update(Key).where(Key.tg_id == tg_id, Key.email == email).values(**update_data)) else: - data = {} - if state: - data = await state.get_data() - - tariff_id = data.get("tariff_id") or tariff_id - new_key = Key( tg_id=tg_id, client_id=client_id, @@ -496,19 +494,17 @@ async def finalize_key_creation( key=public_link, remnawave_link=remnawave_link, server_id=selected_country, - tariff_id=data.get("tariff_id"), + tariff_id=tariff_id, ) session.add(new_key) - data = await state.get_data() - if data.get("is_trial"): + if is_trial: trial_status = await get_trial(session, tg_id) if trial_status in [0, -1]: await update_trial(session, tg_id, 1) - if data.get("tariff_id"): - result = await session.execute( - select(Tariff.price_rub).where(Tariff.id == data["tariff_id"]) - ) + + if tariff_id: + result = await session.execute(select(Tariff.price_rub).where(Tariff.id == tariff_id)) row = result.scalar_one_or_none() if row: await update_balance(session, tg_id, -row) @@ -516,21 +512,13 @@ async def finalize_key_creation( await session.commit() except Exception as e: - logger.error( - f"[Key Finalize] Ошибка при создании ключа для пользователя {tg_id}: {e}" - ) - await callback_query.message.answer( - "❌ Произошла ошибка при создании подписки. Попробуйте снова." - ) + logger.error(f"[Key Finalize] Ошибка при создании ключа для пользователя {tg_id}: {e}") + await callback_query.message.answer("❌ Произошла ошибка при создании подписки. Попробуйте снова.") return builder = InlineKeyboardBuilder() - is_full_remnawave = await is_full_remnawave_cluster( - cluster_info["cluster_name"], session - ) - if (panel_type == "remnawave" or is_full_remnawave) and ( - public_link or remnawave_link - ): + is_full_remnawave = await is_full_remnawave_cluster(cluster_info["cluster_name"], session) + if (panel_type == "remnawave" or is_full_remnawave) and (public_link or remnawave_link): builder.row( InlineKeyboardButton( text=CONNECT_DEVICE, @@ -539,9 +527,7 @@ async def finalize_key_creation( ) elif CONNECT_PHONE_BUTTON: builder.row( - InlineKeyboardButton( - text=CONNECT_PHONE, callback_data=f"connect_phone|{key_name}" - ) + InlineKeyboardButton(text=CONNECT_PHONE, callback_data=f"connect_phone|{key_name}") ) builder.row( InlineKeyboardButton(text=PC_BUTTON, callback_data=f"connect_pc|{email}"), @@ -549,15 +535,10 @@ async def finalize_key_creation( ) else: builder.row( - InlineKeyboardButton( - text=CONNECT_DEVICE, callback_data=f"connect_device|{key_name}" - ) + InlineKeyboardButton(text=CONNECT_DEVICE, callback_data=f"connect_device|{key_name}") ) - builder.row( - InlineKeyboardButton( - text="🔐 Моя подписка", callback_data=f"view_key|{key_name}" - ) - ) + + builder.row(InlineKeyboardButton(text=MY_SUB, callback_data=f"view_key|{key_name}")) builder.row(InlineKeyboardButton(text=SUPPORT, url=SUPPORT_CHAT_URL)) builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile")) diff --git a/handlers/keys/key_utils.py b/handlers/keys/key_utils.py index 42bff44e..1d4720d6 100644 --- a/handlers/keys/key_utils.py +++ b/handlers/keys/key_utils.py @@ -5,7 +5,7 @@ from typing import Any from sqlalchemy import delete, select from sqlalchemy.ext.asyncio import AsyncSession -from config import PUBLIC_LINK, REMNAWAVE_LOGIN, REMNAWAVE_PASSWORD, SUPERNODE +from config import PUBLIC_LINK, REMNAWAVE_LOGIN, REMNAWAVE_PASSWORD, SUPERNODE, TRIAL_CONFIG from database import delete_notification, get_servers, get_tariff_by_id, store_key from database.models import Key, Server, Tariff from handlers.utils import check_server_key_limit, get_least_loaded_cluster @@ -32,7 +32,8 @@ async def create_key_on_cluster( session: AsyncSession = None, remnawave_link: str = None, hwid_limit: int = None, - traffic_limit_bytes: int = None, + traffic_limit_bytes: int = None, + is_trial: bool = False, ): try: servers = await get_servers(session, include_enabled=True) @@ -161,6 +162,7 @@ async def create_key_on_cluster( semaphore, plan=plan, session=session, + is_trial=is_trial, ) else: await asyncio.gather( @@ -174,6 +176,7 @@ async def create_key_on_cluster( semaphore, plan=plan, session=session, + is_trial=is_trial, ) for server in xui_servers ], @@ -207,12 +210,13 @@ async def create_client_on_server( semaphore: asyncio.Semaphore, plan: int = None, session=None, + is_trial: bool = False, ): """ - Создает клиента на указанном 3x-ui сервере с лимитом по тарифу (через ORM). + Создает клиента на указанном 3x-ui сервере с лимитом по тарифу или триалу. """ logger.info( - f"[Client] Вход в create_client_on_server: сервер={server_info.get('server_name')}, план={plan}" + f"[Client] Вход в create_client_on_server: сервер={server_info.get('server_name')}, план={plan}, is_trial={is_trial}" ) async with semaphore: @@ -221,9 +225,7 @@ async def create_client_on_server( server_name = server_info.get("server_name", "unknown") if not inbound_id: - logger.warning( - f"INBOUND_ID отсутствует для сервера {server_name}. Пропуск." - ) + logger.warning(f"[Client] INBOUND_ID отсутствует для сервера {server_name}. Пропуск.") return if SUPERNODE: @@ -236,20 +238,18 @@ async def create_client_on_server( total_gb_value = 0 device_limit_value = None - if plan is not None: + if is_trial: + total_gb_value = int(TRIAL_CONFIG.get("traffic_limit_gb", 0)) * 1024 ** 3 + device_limit_value = TRIAL_CONFIG.get("hwid_limit") + logger.info(f"[Trial] Используются параметры триала: {total_gb_value} байт, {device_limit_value} устройств") + elif plan is not None: tariff = await get_tariff_by_id(session, plan) logger.info(f"[Tariff Debug] Получен тариф: {tariff}") if not tariff: raise ValueError(f"Тариф с id={plan} не найден.") - total_gb_value = ( - int(tariff["traffic_limit"]) if tariff.get("traffic_limit") else 0 - ) - device_limit_value = ( - int(tariff["device_limit"]) - if tariff.get("device_limit") is not None - else None - ) + total_gb_value = int(tariff["traffic_limit"]) if tariff.get("traffic_limit") else 0 + device_limit_value = int(tariff["device_limit"]) if tariff.get("device_limit") is not None else None try: logger.info( @@ -273,9 +273,7 @@ async def create_client_on_server( ) logger.info(f"[Client] Клиент успешно добавлен на сервер {server_name}") except Exception as e: - logger.error( - f"[Client Error] Не удалось создать клиента на {server_name}: {e}" - ) + logger.error(f"[Client Error] Не удалось создать клиента на {server_name}: {e}") if SUPERNODE: await asyncio.sleep(0.7) diff --git a/handlers/payments/gift.cpython-312-x86_64-linux-gnu.so b/handlers/payments/gift.cpython-312-x86_64-linux-gnu.so index 6916e266..b9fed8bd 100644 Binary files a/handlers/payments/gift.cpython-312-x86_64-linux-gnu.so and b/handlers/payments/gift.cpython-312-x86_64-linux-gnu.so differ