aggregated links for update key/ fix router button for country mode
This commit is contained in:
@@ -39,7 +39,7 @@ from database import (
|
||||
update_trial,
|
||||
)
|
||||
from database.models import Key, Server, Tariff
|
||||
from handlers.buttons import BACK, CONNECT_DEVICE, CONNECT_PHONE, MAIN_MENU, MY_SUB, PC_BUTTON, SUPPORT, TV_BUTTON
|
||||
from handlers.buttons import BACK, CONNECT_DEVICE, CONNECT_PHONE, MAIN_MENU, MY_SUB, PC_BUTTON, SUPPORT, TV_BUTTON, ROUTER_BUTTON
|
||||
from handlers.keys.operations import create_client_on_server
|
||||
from handlers.keys.operations.aggregated_links import make_aggregated_link
|
||||
from handlers.texts import SELECT_COUNTRY_MSG, key_message_success
|
||||
@@ -567,9 +567,15 @@ async def finalize_key_creation(
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
is_full_remnawave = await is_full_remnawave_cluster(cluster_name, session)
|
||||
if (panel_type == "remnawave" or is_full_remnawave) and public_link and REMNAWAVE_WEBAPP:
|
||||
builder.row(InlineKeyboardButton(text=CONNECT_DEVICE, web_app=WebAppInfo(url=public_link)))
|
||||
builder.row(InlineKeyboardButton(text=TV_BUTTON, callback_data=f"connect_tv|{email}"))
|
||||
is_vless = bool(public_link and public_link.lower().startswith("vless://")) or bool(need_vless_key)
|
||||
|
||||
if panel_type == "remnawave" or is_full_remnawave:
|
||||
if is_vless:
|
||||
builder.row(InlineKeyboardButton(text=ROUTER_BUTTON, callback_data=f"connect_router|{key_name}"))
|
||||
else:
|
||||
if REMNAWAVE_WEBAPP:
|
||||
builder.row(InlineKeyboardButton(text=CONNECT_DEVICE, web_app=WebAppInfo(url=REMNAWAVE_WEBAPP)))
|
||||
builder.row(InlineKeyboardButton(text=TV_BUTTON, callback_data=f"connect_tv|{email}"))
|
||||
elif CONNECT_PHONE_BUTTON:
|
||||
builder.row(InlineKeyboardButton(text=CONNECT_PHONE, callback_data=f"connect_phone|{key_name}"))
|
||||
builder.row(
|
||||
|
||||
@@ -324,16 +324,18 @@ async def render_key_info(message: Message, session: Any, key_name: str, image_p
|
||||
builder.row(InlineKeyboardButton(text=ROUTER_BUTTON, callback_data=f"connect_router|{key_name}"))
|
||||
else:
|
||||
builder.row(InlineKeyboardButton(text=CONNECT_DEVICE, web_app=WebAppInfo(url=final_link)))
|
||||
builder.row(InlineKeyboardButton(text=TV_BUTTON, callback_data=f"connect_tv|{key_name}"))
|
||||
builder.row(InlineKeyboardButton(text=TV_BUTTON, callback_data=f"connect_tv|{key_name}"))
|
||||
else:
|
||||
if CONNECT_PHONE_BUTTON:
|
||||
builder.row(InlineKeyboardButton(text=CONNECT_PHONE, callback_data=f"connect_phone|{key_name}"))
|
||||
builder.row(
|
||||
InlineKeyboardButton(text=PC_BUTTON, callback_data=f"connect_pc|{key_name}"),
|
||||
InlineKeyboardButton(text=TV_BUTTON, callback_data=f"connect_tv|{key_name}"),
|
||||
)
|
||||
if vless_enabled:
|
||||
builder.row(InlineKeyboardButton(text=PC_BUTTON, callback_data=f"connect_pc|{key_name}"))
|
||||
builder.row(InlineKeyboardButton(text=ROUTER_BUTTON, callback_data=f"connect_router|{key_name}"))
|
||||
else:
|
||||
builder.row(
|
||||
InlineKeyboardButton(text=PC_BUTTON, callback_data=f"connect_pc|{key_name}"),
|
||||
InlineKeyboardButton(text=TV_BUTTON, callback_data=f"connect_tv|{key_name}"),
|
||||
)
|
||||
else:
|
||||
if vless_enabled:
|
||||
builder.row(InlineKeyboardButton(text=ROUTER_BUTTON, callback_data=f"connect_router|{key_name}"))
|
||||
|
||||
@@ -1,23 +1,19 @@
|
||||
import asyncio
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import delete, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from config import PUBLIC_LINK, REMNAWAVE_LOGIN, REMNAWAVE_PASSWORD, SUPERNODE
|
||||
from database import get_servers, store_key
|
||||
from database import get_servers, store_key, filter_cluster_by_subgroup
|
||||
from database.models import Key, Tariff
|
||||
from handlers.utils import get_least_loaded_cluster
|
||||
from logger import (
|
||||
CLOGGER as logger,
|
||||
PANEL_REMNA,
|
||||
PANEL_XUI,
|
||||
)
|
||||
from logger import CLOGGER as logger, PANEL_REMNA, PANEL_XUI
|
||||
from panels._3xui import ClientConfig, add_client, get_xui_instance
|
||||
from panels.remnawave import RemnawaveAPI
|
||||
|
||||
from .deletion import delete_key_from_cluster
|
||||
from .aggregated_links import make_aggregated_link
|
||||
|
||||
|
||||
async def update_key_on_cluster(
|
||||
@@ -30,6 +26,7 @@ async def update_key_on_cluster(
|
||||
traffic_limit: int = None,
|
||||
device_limit: int = None,
|
||||
remnawave_link: str = None,
|
||||
subgroup_code: str | None = None,
|
||||
):
|
||||
try:
|
||||
servers = await get_servers(session)
|
||||
@@ -46,6 +43,13 @@ async def update_key_on_cluster(
|
||||
else:
|
||||
raise ValueError(f"Кластер или сервер с ID/именем {cluster_id} не найден.")
|
||||
|
||||
if subgroup_code:
|
||||
filtered = await filter_cluster_by_subgroup(session, cluster, subgroup_code, cluster_id)
|
||||
if not filtered:
|
||||
logger.warning(f"[Update] Нет серверов для подгруппы {subgroup_code} в кластере {cluster_id}.")
|
||||
return client_id, remnawave_link
|
||||
cluster = filtered
|
||||
|
||||
expire_iso = datetime.utcfromtimestamp(expiry_time / 1000).replace(tzinfo=timezone.utc).isoformat()
|
||||
|
||||
remnawave_servers = [s for s in cluster if s.get("panel_type", "3x-ui").lower() == "remnawave"]
|
||||
@@ -64,13 +68,12 @@ async def update_key_on_cluster(
|
||||
if not group_code:
|
||||
raise ValueError("У Remnawave-сервера отсутствует tariff_group")
|
||||
|
||||
result = await session.execute(
|
||||
_ = await session.execute(
|
||||
select(Tariff)
|
||||
.where(Tariff.group_code == group_code, Tariff.is_active.is_(True))
|
||||
.order_by(Tariff.duration_days.desc())
|
||||
.limit(1)
|
||||
)
|
||||
result.scalar_one_or_none()
|
||||
|
||||
short_uuid = None
|
||||
if remnawave_link and "/" in remnawave_link:
|
||||
@@ -124,13 +127,12 @@ async def update_key_on_cluster(
|
||||
if not group_code:
|
||||
raise ValueError(f"У сервера {server_name} отсутствует tariff_group")
|
||||
|
||||
result = await session.execute(
|
||||
_ = await session.execute(
|
||||
select(Tariff)
|
||||
.where(Tariff.group_code == group_code, Tariff.is_active.is_(True))
|
||||
.order_by(Tariff.duration_days.desc())
|
||||
.limit(1)
|
||||
)
|
||||
result.scalar_one_or_none()
|
||||
|
||||
total_gb_bytes = int(traffic_limit * 1024**3) if traffic_limit is not None else 0
|
||||
device_limit_value = device_limit if device_limit is not None else 0
|
||||
@@ -153,7 +155,7 @@ async def update_key_on_cluster(
|
||||
if tasks:
|
||||
await asyncio.gather(*tasks, return_exceptions=True)
|
||||
|
||||
logger.info(f"[Update] Ключ {remnawave_client_id} обновлён на всех серверах кластера {cluster_id}")
|
||||
logger.info(f"[Update] Ключ {remnawave_client_id} обновлён на серверах подгруппы в {cluster_id}")
|
||||
return remnawave_client_id, remnawave_key
|
||||
|
||||
except Exception as e:
|
||||
@@ -171,7 +173,6 @@ async def update_subscription(
|
||||
) -> None:
|
||||
result = await session.execute(select(Key).where(Key.tg_id == tg_id, Key.email == email))
|
||||
record = result.scalar_one_or_none()
|
||||
|
||||
if not record:
|
||||
raise ValueError(f"The key {email} does not exist in database")
|
||||
|
||||
@@ -183,16 +184,17 @@ async def update_subscription(
|
||||
remnawave_link = remnawave_link or record.remnawave_link
|
||||
public_link = f"{PUBLIC_LINK}{email}/{tg_id}"
|
||||
|
||||
traffic_limit = None
|
||||
device_limit = None
|
||||
tariff = None
|
||||
subgroup_code = getattr(record, "subgroup_code", None)
|
||||
|
||||
if tariff_id:
|
||||
result = await session.execute(select(Tariff).where(Tariff.id == tariff_id, Tariff.is_active.is_(True)))
|
||||
tariff = result.scalar_one_or_none()
|
||||
if tariff:
|
||||
traffic_limit = int(tariff.traffic_limit) if tariff.traffic_limit is not None else None
|
||||
device_limit = int(tariff.device_limit) if tariff.device_limit is not None else 0
|
||||
else:
|
||||
q = await session.execute(select(Tariff).where(Tariff.id == tariff_id, Tariff.is_active.is_(True)))
|
||||
tariff = q.scalar_one_or_none()
|
||||
if tariff is None:
|
||||
logger.warning(f"[LOG] update_subscription: тариф с id={tariff_id} не найден!")
|
||||
else:
|
||||
if not subgroup_code:
|
||||
subgroup_code = getattr(tariff, "subgroup_code", None) or getattr(tariff, "subgroup_title", None)
|
||||
else:
|
||||
logger.warning("[LOG] update_subscription: tariff_id отсутствует!")
|
||||
|
||||
@@ -209,18 +211,6 @@ async def update_subscription(
|
||||
logger.warning("[Update] Нет доступных кластеров, оставляем на старом")
|
||||
new_cluster_id = old_cluster_id
|
||||
|
||||
new_client_id, remnawave_key = await update_key_on_cluster(
|
||||
tg_id=tg_id,
|
||||
client_id=client_id,
|
||||
email=email,
|
||||
expiry_time=expiry_time,
|
||||
cluster_id=new_cluster_id,
|
||||
session=session,
|
||||
traffic_limit=traffic_limit,
|
||||
device_limit=device_limit,
|
||||
remnawave_link=remnawave_link,
|
||||
)
|
||||
|
||||
servers = await get_servers(session)
|
||||
cluster_servers = servers.get(new_cluster_id)
|
||||
|
||||
@@ -235,8 +225,45 @@ async def update_subscription(
|
||||
else:
|
||||
cluster_servers = []
|
||||
|
||||
has_xui = any(s.get("panel_type", "").lower() == "3x-ui" for s in cluster_servers)
|
||||
final_key_link = public_link if has_xui else None
|
||||
if subgroup_code:
|
||||
prefiltered = await filter_cluster_by_subgroup(session, cluster_servers, subgroup_code, new_cluster_id)
|
||||
if not prefiltered:
|
||||
logger.warning(f"[Update] Пересоздание пропущено: нет серверов под подгруппу {subgroup_code} в {new_cluster_id}.")
|
||||
return
|
||||
cluster_servers = prefiltered
|
||||
|
||||
traffic_limit = None
|
||||
device_limit = None
|
||||
if tariff:
|
||||
traffic_limit = int(tariff.traffic_limit) if tariff.traffic_limit is not None else None
|
||||
device_limit = int(tariff.device_limit) if tariff.device_limit is not None else 0
|
||||
|
||||
new_client_id, remnawave_key = await update_key_on_cluster(
|
||||
tg_id=tg_id,
|
||||
client_id=client_id,
|
||||
email=email,
|
||||
expiry_time=expiry_time,
|
||||
cluster_id=new_cluster_id,
|
||||
session=session,
|
||||
traffic_limit=traffic_limit,
|
||||
device_limit=device_limit,
|
||||
remnawave_link=remnawave_link,
|
||||
subgroup_code=subgroup_code,
|
||||
)
|
||||
|
||||
aggregated = await make_aggregated_link(
|
||||
session=session,
|
||||
cluster_all=cluster_servers,
|
||||
cluster_id=new_cluster_id,
|
||||
email=email,
|
||||
client_id=new_client_id,
|
||||
tg_id=tg_id,
|
||||
subgroup_code=subgroup_code,
|
||||
remna_link_override=remnawave_key,
|
||||
plan=tariff_id,
|
||||
)
|
||||
|
||||
final_key_link = aggregated or public_link
|
||||
|
||||
await store_key(
|
||||
session=session,
|
||||
|
||||
Reference in New Issue
Block a user