add support traffic for trial in cluster mode/country mode

This commit is contained in:
Vladless
2025-05-26 21:37:00 +03:00
parent daa9710579
commit 3e33513fe9
4 changed files with 73 additions and 90 deletions
+6 -2
View File
@@ -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(
+50 -69
View File
@@ -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"))
+17 -19
View File
@@ -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)