Compare commits
No commits in common. "54e6f938e700cbd24920d913bbc991f857217cf5" and "ebf1167fea13bcfd0b46a28b4471acafac940d33" have entirely different histories.
54e6f938e7
...
ebf1167fea
@ -40,7 +40,7 @@ class ClientHandlers:
|
|||||||
await message.answer(f"❌ Произошла ошибка при создании профиля. Попробуйте позже.\n {e}")
|
await message.answer(f"❌ Произошла ошибка при создании профиля. Попробуйте позже.\n {e}")
|
||||||
|
|
||||||
async def cmd_info(self, message: types.Message):
|
async def cmd_info(self, message: types.Message):
|
||||||
"""Обработчик команды /info с выводом конфига и статистики."""
|
"""Обработчик команды /info."""
|
||||||
args = (message.text or "").strip().split(maxsplit=1)
|
args = (message.text or "").strip().split(maxsplit=1)
|
||||||
if len(args) < 2:
|
if len(args) < 2:
|
||||||
await message.answer(
|
await message.answer(
|
||||||
@ -52,50 +52,23 @@ class ClientHandlers:
|
|||||||
telegram_id = args[1].lstrip("@").strip()
|
telegram_id = args[1].lstrip("@").strip()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
(vless_client, vless_stats), (ss_client, ss_stats) = \
|
vless_client, ss_client = self.client_service.get_client_info(telegram_id)
|
||||||
self.client_service.get_client_info_with_stats(telegram_id)
|
|
||||||
|
|
||||||
def format_info(client, stats, name):
|
def format_info(client, name):
|
||||||
if not client:
|
if not client:
|
||||||
return f"❌ Клиент <b>{name}</b> не найден.\n"
|
return f"❌ Клиент <b>{name}</b> не найден.\n"
|
||||||
|
|
||||||
# Конфиг клиента
|
|
||||||
json_info = json.dumps(client, ensure_ascii=False, indent=2)
|
json_info = json.dumps(client, ensure_ascii=False, indent=2)
|
||||||
text = f"🔹 <b>{name}</b>:\n<pre>{json_info}</pre>"
|
return f"🔹 <b>{name}</b>:\n<pre>{json_info}</pre>"
|
||||||
|
|
||||||
# Статистика
|
|
||||||
if stats:
|
|
||||||
up = stats.get("up", 0)
|
|
||||||
down = stats.get("down", 0)
|
|
||||||
total = up + down
|
|
||||||
|
|
||||||
def human_size(num):
|
|
||||||
for unit in ["B", "KB", "MB", "GB", "TB"]:
|
|
||||||
if num < 1024:
|
|
||||||
return f"{num:.2f} {unit}"
|
|
||||||
num /= 1024
|
|
||||||
return f"{num:.2f} PB"
|
|
||||||
|
|
||||||
text += (
|
|
||||||
f"\n📊 Трафик: ↑ {human_size(up)} / ↓ {human_size(down)}"
|
|
||||||
f" (Σ {human_size(total)})"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
text += "\n📊 Статистика не найдена."
|
|
||||||
|
|
||||||
return text
|
|
||||||
|
|
||||||
response = (
|
response = (
|
||||||
format_info(vless_client, vless_stats, "VLESS")
|
format_info(vless_client, "VLESS") +
|
||||||
+ "\n\n"
|
"\n\n" +
|
||||||
+ format_info(ss_client, ss_stats, "Shadowsocks")
|
format_info(ss_client, "Shadowsocks")
|
||||||
)
|
)
|
||||||
|
|
||||||
await message.answer(response, parse_mode=ParseMode.HTML)
|
await message.answer(response, parse_mode=ParseMode.HTML)
|
||||||
|
|
||||||
except BadLogin:
|
except BadLogin:
|
||||||
await message.answer("❌ Ошибка входа в панель XUI.")
|
await message.answer("❌ Ошибка входа в панель XUI.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Ошибка получения информации: {e}")
|
logger.error(f"Ошибка получения информации: {e}")
|
||||||
await message.answer("❌ Ошибка при получении информации. Проверь лог.")
|
await message.answer("❌ Ошибка при получении информации. Проверь лог.")
|
||||||
|
|
||||||
@ -132,20 +132,10 @@ class ClientService:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
async def create_client_profile(self, telegram_id: str) -> Tuple[bool, str]:
|
async def create_client_profile(self, telegram_id: str) -> Tuple[bool, str]:
|
||||||
"""Создание полного профиля клиента (VLESS + Shadowsocks) с проверкой существующего."""
|
"""Создание полного профиля клиента (VLESS + Shadowsocks)."""
|
||||||
try:
|
try:
|
||||||
# Сначала проверяем, есть ли уже клиенты
|
|
||||||
vless_client, ss_client = self.get_client_info(telegram_id)
|
|
||||||
if vless_client or ss_client:
|
|
||||||
subscription_link = self.get_subscription_link(telegram_id)
|
|
||||||
logger.info(f"Клиент для {telegram_id} уже существует.")
|
|
||||||
return True, (
|
|
||||||
f"ℹ Клиент для <b>{telegram_id}</b> уже существует.\n"
|
|
||||||
f"🔗 Подписочная ссылка:\n<code>{subscription_link}</code>"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Генерируем новые креды
|
|
||||||
vless_email, ss_email, vless_uuid, ss_password = self.generate_client_credentials(telegram_id)
|
vless_email, ss_email, vless_uuid, ss_password = self.generate_client_credentials(telegram_id)
|
||||||
|
|
||||||
logger.info(f"Создаём клиентов для telegram_id={telegram_id}")
|
logger.info(f"Создаём клиентов для telegram_id={telegram_id}")
|
||||||
|
|
||||||
# Создаём VLESS клиента
|
# Создаём VLESS клиента
|
||||||
@ -161,13 +151,13 @@ class ClientService:
|
|||||||
|
|
||||||
# Создаём Shadowsocks клиента
|
# Создаём Shadowsocks клиента
|
||||||
ss_success = await self.create_shadowsocks_client(telegram_id, ss_password)
|
ss_success = await self.create_shadowsocks_client(telegram_id, ss_password)
|
||||||
|
|
||||||
if not ss_success:
|
if not ss_success:
|
||||||
return False, "Ошибка при создании Shadowsocks клиента"
|
return False, "Ошибка при создании Shadowsocks клиента"
|
||||||
|
|
||||||
# Подписочная ссылка
|
|
||||||
subscription_link = self.get_subscription_link(telegram_id)
|
subscription_link = self.get_subscription_link(telegram_id)
|
||||||
success_message = (
|
success_message = (
|
||||||
f"✅ Профиль для <b>{telegram_id}</b> успешно создан!\n"
|
f"✅ Профиль для {telegram_id} успешно создан!\n"
|
||||||
f"🔗 Подписочная ссылка:\n<code>{subscription_link}</code>"
|
f"🔗 Подписочная ссылка:\n<code>{subscription_link}</code>"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -177,43 +167,6 @@ class ClientService:
|
|||||||
logger.error(f"Ошибка при создании профиля: {e}")
|
logger.error(f"Ошибка при создании профиля: {e}")
|
||||||
return False, "Произошла ошибка при создании профиля"
|
return False, "Произошла ошибка при создании профиля"
|
||||||
|
|
||||||
|
|
||||||
# async def create_client_profile(self, telegram_id: str) -> Tuple[bool, str]:
|
|
||||||
# """Создание полного профиля клиента (VLESS + Shadowsocks)."""
|
|
||||||
# try:
|
|
||||||
# vless_email, ss_email, vless_uuid, ss_password = self.generate_client_credentials(telegram_id)
|
|
||||||
#
|
|
||||||
# logger.info(f"Создаём клиентов для telegram_id={telegram_id}")
|
|
||||||
#
|
|
||||||
# # Создаём VLESS клиента
|
|
||||||
# vless_success = self.xui_service.add_vless_client(
|
|
||||||
# inbound_id=INBOUND_VLESS_ID,
|
|
||||||
# email=vless_email,
|
|
||||||
# uuid=vless_uuid,
|
|
||||||
# telegram_id=telegram_id
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
# if not vless_success:
|
|
||||||
# return False, "Ошибка при создании VLESS клиента"
|
|
||||||
#
|
|
||||||
# # Создаём Shadowsocks клиента
|
|
||||||
# ss_success = await self.create_shadowsocks_client(telegram_id, ss_password)
|
|
||||||
#
|
|
||||||
# if not ss_success:
|
|
||||||
# return False, "Ошибка при создании Shadowsocks клиента"
|
|
||||||
#
|
|
||||||
# subscription_link = self.get_subscription_link(telegram_id)
|
|
||||||
# success_message = (
|
|
||||||
# f"✅ Профиль для {telegram_id} успешно создан!\n"
|
|
||||||
# f"🔗 Подписочная ссылка:\n<code>{subscription_link}</code>"
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
# return True, success_message
|
|
||||||
#
|
|
||||||
# except Exception as e:
|
|
||||||
# logger.error(f"Ошибка при создании профиля: {e}")
|
|
||||||
# return False, "Произошла ошибка при создании профиля"
|
|
||||||
|
|
||||||
def get_client_info(self, telegram_id: str) -> Tuple[Optional[Dict[str, Any]], Optional[Dict[str, Any]]]:
|
def get_client_info(self, telegram_id: str) -> Tuple[Optional[Dict[str, Any]], Optional[Dict[str, Any]]]:
|
||||||
"""Получение информации о клиентах."""
|
"""Получение информации о клиентах."""
|
||||||
vless_email = f"{telegram_id}_vl_ssl"
|
vless_email = f"{telegram_id}_vl_ssl"
|
||||||
@ -222,25 +175,4 @@ class ClientService:
|
|||||||
vless_client = self.xui_service.get_client(INBOUND_VLESS_ID, vless_email)
|
vless_client = self.xui_service.get_client(INBOUND_VLESS_ID, vless_email)
|
||||||
ss_client = self.xui_service.get_client(INBOUND_SS_ID, ss_email)
|
ss_client = self.xui_service.get_client(INBOUND_SS_ID, ss_email)
|
||||||
|
|
||||||
return vless_client, ss_client
|
return vless_client, ss_client
|
||||||
|
|
||||||
def get_client_info_with_stats(self, telegram_id: str):
|
|
||||||
"""Возвращает клиентов и их статистику по Telegram ID."""
|
|
||||||
vless_client, ss_client = self.get_client_info(telegram_id)
|
|
||||||
|
|
||||||
vless_stats = None
|
|
||||||
ss_stats = None
|
|
||||||
|
|
||||||
if vless_client:
|
|
||||||
vless_stats = self.xui_service.get_client_stats(
|
|
||||||
inbound_id=INBOUND_VLESS_ID,
|
|
||||||
email=vless_client["email"]
|
|
||||||
)
|
|
||||||
|
|
||||||
if ss_client:
|
|
||||||
ss_stats = self.xui_service.get_client_stats(
|
|
||||||
inbound_id=INBOUND_SS_ID,
|
|
||||||
email=ss_client["email"]
|
|
||||||
)
|
|
||||||
|
|
||||||
return (vless_client, vless_stats), (ss_client, ss_stats)
|
|
||||||
@ -40,58 +40,14 @@ class XUIService:
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
def get_client(self, inbound_id: int, email: str) -> Optional[Dict[str, Any]]:
|
def get_client(self, inbound_id: int, email: str) -> Optional[Dict[str, Any]]:
|
||||||
"""Получение информации о клиенте (работает и для SS, и для VLESS)."""
|
"""Получение информации о клиенте."""
|
||||||
try:
|
try:
|
||||||
self.login()
|
self.login()
|
||||||
inbounds = self.xui.get_inbounds()
|
return self.xui.get_client(inbound_id=inbound_id, email=email)
|
||||||
if "obj" not in inbounds:
|
|
||||||
logger.error("Некорректный ответ от XUI при запросе inbounds")
|
|
||||||
return None
|
|
||||||
|
|
||||||
for inbound in inbounds["obj"]:
|
|
||||||
if inbound["id"] != inbound_id:
|
|
||||||
continue
|
|
||||||
|
|
||||||
settings = json.loads(inbound["settings"])
|
|
||||||
for client in settings.get("clients", []):
|
|
||||||
if client.get("email") == email:
|
|
||||||
# У SS-клиентов id нет — подставляем email
|
|
||||||
if "id" not in client:
|
|
||||||
client["id"] = client["email"]
|
|
||||||
return client
|
|
||||||
|
|
||||||
logger.warning(f"Клиент {email} не найден в inbound {inbound_id}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Ошибка получения клиента {email}: {e}")
|
logger.error(f"Ошибка получения клиента {email}: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_client_stats(self, inbound_id: int, email: str) -> Optional[Dict[str, Any]]:
|
|
||||||
"""Получение статистики клиента по inbound и email."""
|
|
||||||
try:
|
|
||||||
self.login()
|
|
||||||
inbounds = self.xui.get_inbounds()
|
|
||||||
if "obj" not in inbounds:
|
|
||||||
logger.error("Некорректный ответ от XUI при запросе inbounds")
|
|
||||||
return None
|
|
||||||
|
|
||||||
for inbound in inbounds["obj"]:
|
|
||||||
if inbound["id"] != inbound_id:
|
|
||||||
continue
|
|
||||||
|
|
||||||
for client_stat in inbound.get("clientStats", []):
|
|
||||||
if client_stat.get("email") == email:
|
|
||||||
return client_stat
|
|
||||||
|
|
||||||
logger.warning(f"Статистика по клиенту {email} не найдена в inbound {inbound_id}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Ошибка получения статистики клиента {email}: {e}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def add_vless_client(
|
def add_vless_client(
|
||||||
self,
|
self,
|
||||||
inbound_id: int,
|
inbound_id: int,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user