on/off server in cluster

This commit is contained in:
Vladless
2025-04-17 15:02:54 +03:00
parent 6be48eb828
commit 45fd8fe221
5 changed files with 73 additions and 16 deletions
+3
View File
@@ -133,6 +133,9 @@ CREATE TABLE IF NOT EXISTS servers
ALTER TABLE servers ADD COLUMN IF NOT EXISTS panel_type TEXT NOT NULL DEFAULT '3x-ui';
ALTER TABLE servers
ALTER COLUMN subscription_url DROP NOT NULL;
ALTER TABLE servers
ADD COLUMN IF NOT EXISTS enabled BOOLEAN NOT NULL DEFAULT TRUE;
CREATE TABLE IF NOT EXISTS gifts
+11 -6
View File
@@ -1341,17 +1341,21 @@ async def get_last_notification_time(tg_id: int, notification_type: str, session
await conn.close()
async def get_servers(session: Any = None):
async def get_servers(session: Any = None, include_enabled: bool = False):
conn = None
try:
conn = session if session is not None else await asyncpg.connect(DATABASE_URL)
result = await conn.fetch(
"""
query = """
SELECT cluster_name, server_name, api_url, subscription_url, inbound_id, panel_type
FROM servers
"""
)
"""
if include_enabled:
query += ", enabled"
query += " FROM servers"
result = await conn.fetch(query)
servers = {}
for row in result:
cluster_name = row["cluster_name"]
@@ -1364,6 +1368,7 @@ async def get_servers(session: Any = None):
"subscription_url": row["subscription_url"],
"inbound_id": row["inbound_id"],
"panel_type": row["panel_type"],
"enabled": row.get("enabled", True),
})
return servers
+10 -4
View File
@@ -10,14 +10,20 @@ class AdminServerCallback(CallbackData, prefix="admin_server"):
data: str
def build_manage_server_kb(server_name: str, cluster_name: str) -> InlineKeyboardMarkup:
def build_manage_server_kb(server_name: str, cluster_name: str, enabled: bool) -> InlineKeyboardMarkup:
from ..clusters.keyboard import AdminClusterCallback
builder = InlineKeyboardBuilder()
builder.button(text="🗑️ Удалить", callback_data=AdminServerCallback(action="delete", data=server_name).pack())
toggle_text = "🔴 Отключить" if enabled else "🟢 Включить"
toggle_action = "disable" if enabled else "enable"
builder.button(
text="✏️ Сменить название", callback_data=AdminServerCallback(action="rename", data=server_name).pack()
text=toggle_text, callback_data=AdminServerCallback(action=toggle_action, data=server_name).pack()
)
builder.button(text="🗑️ Удалить", callback_data=AdminServerCallback(action="delete", data=server_name).pack())
builder.button(text="✏️ Сменить название", callback_data=AdminServerCallback(action="rename", data=server_name).pack())
builder.button(text=BACK, callback_data=AdminClusterCallback(action="manage", data=cluster_name).pack())
builder.adjust(1)
return builder.as_markup()
return builder.as_markup()
+41 -3
View File
@@ -5,7 +5,7 @@ from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery, InlineKeyboardButton
from aiogram.utils.keyboard import InlineKeyboardBuilder
from database import delete_server, get_servers
from database import get_servers
from filters.admin import IsAdminFilter
from handlers.buttons import BACK
@@ -22,7 +22,7 @@ router = Router()
@router.callback_query(AdminServerCallback.filter(F.action == "manage"), IsAdminFilter())
async def handle_server_manage(callback_query: CallbackQuery, callback_data: AdminServerCallback):
server_name = callback_data.data
servers = await get_servers()
servers = await get_servers(include_enabled=True)
cluster_name, server = next(
((c, s) for c, cs in servers.items() for s in cs if s["server_name"] == server_name), (None, None)
@@ -42,7 +42,7 @@ async def handle_server_manage(callback_query: CallbackQuery, callback_data: Adm
await callback_query.message.edit_text(
text=text,
reply_markup=build_manage_server_kb(server_name, cluster_name),
reply_markup=build_manage_server_kb(server_name, cluster_name, enabled=server.get("enabled", True)),
)
else:
await callback_query.message.edit_text(text="❌ Сервер не найден.")
@@ -170,3 +170,41 @@ async def process_callback_delete_server(
text=f"✅ Сервер '{server_name}' удален.",
reply_markup=build_admin_back_kb("clusters"),
)
@router.callback_query(
AdminServerCallback.filter(F.action.in_(["enable", "disable"])), IsAdminFilter()
)
async def toggle_server_enabled(callback_query: CallbackQuery, callback_data: AdminServerCallback, session: Any):
server_name = callback_data.data
action = callback_data.action
new_status = action == "enable"
await session.execute(
"UPDATE servers SET enabled = $1 WHERE server_name = $2",
new_status,
server_name
)
servers = await get_servers(include_enabled=True)
cluster_name, server = next(
((c, s) for c, cs in servers.items() for s in cs if s["server_name"] == server_name), (None, None)
)
if not server:
await callback_query.message.edit_text("❌ Сервер не найден.")
return
text = (
f"<b>🔧 Информация о сервере {server_name}:</b>\n\n"
f"<b>📡 API URL:</b> {server['api_url']}\n"
f"<b>🌐 Subscription URL:</b> {server['subscription_url']}\n"
f"<b>🔑 Inbound ID:</b> {server['inbound_id']}"
)
await callback_query.message.edit_text(
text=text,
reply_markup=build_manage_server_kb(server_name, cluster_name, enabled=new_status)
)
+8 -3
View File
@@ -43,7 +43,7 @@ async def create_key_on_cluster(
remnawave_link: str = None,
):
try:
servers = await get_servers()
servers = await get_servers(include_enabled=True)
cluster = servers.get(cluster_id)
server_id_to_store = cluster_id
@@ -59,10 +59,15 @@ async def create_key_on_cluster(
else:
raise ValueError(f"Кластер или сервер с ID/именем {cluster_id} не найден.")
enabled_servers = [s for s in cluster if s.get("enabled", True)]
if not enabled_servers:
logger.warning(f"[Key Creation] Нет доступных серверов в кластере {cluster_id}")
return
semaphore = asyncio.Semaphore(2)
remnawave_servers = [s for s in cluster if s.get("panel_type", "3x-ui").lower() == "remnawave"]
xui_servers = [s for s in cluster if s.get("panel_type", "3x-ui").lower() == "3x-ui"]
remnawave_servers = [s for s in enabled_servers if s.get("panel_type", "3x-ui").lower() == "remnawave"]
xui_servers = [s for s in enabled_servers if s.get("panel_type", "3x-ui").lower() == "3x-ui"]
remnawave_created = False
remnawave_key = None