Add bulk cluster extend / HWID reset on device limit downgrade

This commit is contained in:
Capybara-z
2026-01-16 01:06:39 +03:00
parent abd0315244
commit d88d1d9482
3 changed files with 105 additions and 37 deletions
+89 -36
View File
@@ -147,46 +147,99 @@ async def handle_days_input(message: Message, state: FSMContext, session: AsyncS
await state.clear() await state.clear()
return return
for key in keys: servers = await get_servers(session=session)
new_expiry = key.expiry_time + add_ms cluster_servers = servers.get(cluster_name, [])
traffic_limit = 0 if not cluster_servers:
device_limit = 0 await message.answer("❌ Не найдены серверы в кластере.")
key_subgroup = None await state.clear()
if key.tariff_id: return
result = await session.execute(
select(Tariff.traffic_limit, Tariff.device_limit, Tariff.subgroup_title).where(
Tariff.id == key.tariff_id,
Tariff.is_active.is_(True),
)
)
tariff = result.first()
if tariff:
traffic_limit = int(tariff[0]) if tariff[0] is not None else 0
device_limit = int(tariff[1]) if tariff[1] is not None else 0
key_subgroup = tariff[2]
await renew_key_in_cluster( is_full_remnawave = all(
cluster_name, str(s.get("panel_type", "")).lower() == "remnawave"
email=key.email, for s in cluster_servers
client_id=key.client_id,
new_expiry_time=new_expiry,
total_gb=traffic_limit,
session=session,
hwid_device_limit=device_limit,
reset_traffic=False,
target_subgroup=key_subgroup,
old_subgroup=key_subgroup,
plan=key.tariff_id,
)
await update_key_expiry(session, key.client_id, new_expiry)
logger.info(f"[Cluster Extend] {key.email} +{days}д → {datetime.utcfromtimestamp(new_expiry / 1000)}")
await message.answer(
f"✅ Время подписки продлено на <b>{days} дней</b> всем пользователям в кластере <b>{cluster_name}</b>."
) )
if is_full_remnawave:
uuids = [key.client_id for key in keys if key.client_id]
if not uuids:
await message.answer("❌ Нет валидных подписок для продления.")
await state.clear()
return
api_url = cluster_servers[0].get("api_url", "")
if not api_url:
await message.answer("❌ Не найден URL панели для кластера.")
await state.clear()
return
from panels.remnawave import RemnawaveAPI
remna = RemnawaveAPI(api_url)
try:
result_bulk = await remna.bulk_extend_expiration_date(uuids, days)
finally:
await remna.aclose()
if result_bulk is None:
await message.answer("❌ Ошибка при обращении к API панели.")
await state.clear()
return
affected = result_bulk.get("affectedRows", 0)
logger.info(f"[Cluster Extend] Bulk API: продлено {affected} подписок на {days} дней")
for key in keys:
new_expiry = key.expiry_time + add_ms
await update_key_expiry(session, key.client_id, new_expiry)
await session.commit()
await message.answer(
f"✅ Время подписки продлено на <b>{days} дней</b> для <b>{affected}</b> пользователей в кластере <b>{cluster_name}</b>."
)
else:
for key in keys:
new_expiry = key.expiry_time + add_ms
traffic_limit = 0
device_limit = 0
key_subgroup = None
if key.tariff_id:
tariff_result = await session.execute(
select(Tariff.traffic_limit, Tariff.device_limit, Tariff.subgroup_title).where(
Tariff.id == key.tariff_id,
Tariff.is_active.is_(True),
)
)
tariff = tariff_result.first()
if tariff:
traffic_limit = int(tariff[0]) if tariff[0] is not None else 0
device_limit = int(tariff[1]) if tariff[1] is not None else 0
key_subgroup = tariff[2]
await renew_key_in_cluster(
cluster_name,
email=key.email,
client_id=key.client_id,
new_expiry_time=new_expiry,
total_gb=traffic_limit,
session=session,
hwid_device_limit=device_limit,
reset_traffic=False,
target_subgroup=key_subgroup,
old_subgroup=key_subgroup,
plan=key.tariff_id,
)
await update_key_expiry(session, key.client_id, new_expiry)
logger.info(f"[Cluster Extend] {key.email} +{days}д → {datetime.utcfromtimestamp(new_expiry / 1000)}")
await message.answer(
f"✅ Время подписки продлено на <b>{days} дней</b> всем пользователям в кластере <b>{cluster_name}</b>."
)
except ValueError: except ValueError:
await message.answer("❌ Введите корректное число дней.") await message.answer("❌ Введите корректное число дней.")
except Exception as e: except Exception as e:
+15
View File
@@ -58,6 +58,7 @@ async def renew_on_remnawave(
reset_traffic: bool, reset_traffic: bool,
target_server_name: str | None = None, target_server_name: str | None = None,
external_squad_uuid: str | None = None, external_squad_uuid: str | None = None,
old_device_limit: int | None = None,
) -> bool: ) -> bool:
remnawave_nodes = [ remnawave_nodes = [
s for s in cluster if str(s.get("panel_type", "3x-ui")).lower() == "remnawave" and s.get("inbound_id") s for s in cluster if str(s.get("panel_type", "3x-ui")).lower() == "remnawave" and s.get("inbound_id")
@@ -74,6 +75,13 @@ async def renew_on_remnawave(
logger.error(f"{PANEL_REMNA} Не удалось войти в Remnawave API") logger.error(f"{PANEL_REMNA} Не удалось войти в Remnawave API")
return False return False
if old_device_limit is not None and hwid_device_limit < old_device_limit:
try:
await remna.clear_all_hwid_devices(client_id)
logger.info(f"{PANEL_REMNA} HWID устройства сброшены для {client_id} (лимит {old_device_limit}{hwid_device_limit})")
except Exception as e:
logger.warning(f"{PANEL_REMNA} Ошибка сброса HWID: {e}")
expire_iso = datetime.utcfromtimestamp(new_expiry_time // 1000).isoformat() + "Z" expire_iso = datetime.utcfromtimestamp(new_expiry_time // 1000).isoformat() + "Z"
traffic_limit_bytes = total_gb * 1024 * 1024 * 1024 if total_gb else 0 traffic_limit_bytes = total_gb * 1024 * 1024 * 1024 if total_gb else 0
active_inbounds = [s["inbound_id"] for s in remnawave_nodes] active_inbounds = [s["inbound_id"] for s in remnawave_nodes]
@@ -203,6 +211,12 @@ async def renew_key_in_cluster(
tg_id = int(kd["tg_id"]) tg_id = int(kd["tg_id"])
server_id = kd["server_id"] server_id = kd["server_id"]
old_device_limit = kd.get("current_device_limit") or kd.get("selected_device_limit")
if old_device_limit is None and kd.get("tariff_id"):
old_tariff = await get_tariff_by_id(session, kd["tariff_id"])
if old_tariff:
old_device_limit = old_tariff.get("device_limit")
single_server = None single_server = None
if servers_map.get(server_id): if servers_map.get(server_id):
cluster = servers_map[server_id] cluster = servers_map[server_id]
@@ -330,6 +344,7 @@ async def renew_key_in_cluster(
reset_traffic=reset_traffic, reset_traffic=reset_traffic,
target_server_name=server_id if single_server else None, target_server_name=server_id if single_server else None,
external_squad_uuid=external_squad_uuid, external_squad_uuid=external_squad_uuid,
old_device_limit=old_device_limit,
) )
succeeded, _ = await renew_on_3xui( succeeded, _ = await renew_on_3xui(
Binary file not shown.