129 lines
4.3 KiB
Python
129 lines
4.3 KiB
Python
import json
|
|
import sqlite3
|
|
import time
|
|
|
|
from datetime import datetime
|
|
from itertools import cycle
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.exc import SQLAlchemyError
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from config import USE_COUNTRY_SELECTION
|
|
from core.bootstrap import MODES_CONFIG
|
|
from database.models import Key, Server, User
|
|
|
|
|
|
async def import_keys_from_3xui_db(db_path: str, session: AsyncSession) -> tuple[int, int]:
|
|
imported = 0
|
|
skipped = 0
|
|
|
|
use_country_selection = bool(MODES_CONFIG.get("COUNTRY_SELECTION_ENABLED", USE_COUNTRY_SELECTION))
|
|
|
|
if use_country_selection:
|
|
result = await session.execute(
|
|
select(Server.server_name).where(Server.enabled.is_(True), Server.panel_type == "3x-ui")
|
|
)
|
|
else:
|
|
result = await session.execute(
|
|
select(Server.cluster_name)
|
|
.where(Server.enabled.is_(True), Server.panel_type == "3x-ui", Server.cluster_name.isnot(None))
|
|
.distinct()
|
|
)
|
|
|
|
server_ids = [row[0] for row in result.fetchall()]
|
|
if not server_ids:
|
|
raise RuntimeError("❌ Не найдено доступных серверов или кластеров для 3x-ui")
|
|
|
|
server_cycle = cycle(server_ids)
|
|
|
|
try:
|
|
conn = sqlite3.connect(db_path)
|
|
cursor = conn.cursor()
|
|
cursor.execute("SELECT id, remark, settings FROM inbounds")
|
|
inbounds = cursor.fetchall()
|
|
except Exception as e:
|
|
raise RuntimeError(f"Не удалось прочитать SQLite: {e}")
|
|
finally:
|
|
conn.close()
|
|
|
|
parsed_clients = []
|
|
for inbound_id, _remark, settings_raw in inbounds:
|
|
try:
|
|
settings = json.loads(settings_raw)
|
|
clients = settings.get("clients", [])
|
|
for c in clients:
|
|
expiry = c.get("expiryTime")
|
|
c["expiryTime"] = int(float(expiry)) if expiry else 0
|
|
c["limitIp"] = int(c.get("limitIp", 0) or 0)
|
|
c["inbound_id"] = inbound_id
|
|
parsed_clients.append(c)
|
|
except Exception:
|
|
continue
|
|
|
|
now_ts = int(time.time() * 1000)
|
|
|
|
for c in parsed_clients:
|
|
tg_id = c.get("tgId")
|
|
client_id = str(c.get("id"))
|
|
email = c.get("email")
|
|
expiry_time = int(c.get("expiryTime") or now_ts)
|
|
created_at = now_ts
|
|
server_id = next(server_cycle)
|
|
|
|
if not tg_id or not client_id:
|
|
continue
|
|
|
|
user_exists = await session.execute(select(User).where(User.tg_id == tg_id))
|
|
if not user_exists.scalar():
|
|
try:
|
|
session.add(
|
|
User(
|
|
tg_id=tg_id,
|
|
username=None,
|
|
first_name=None,
|
|
last_name=None,
|
|
language_code=None,
|
|
is_bot=False,
|
|
balance=0.0,
|
|
trial=1,
|
|
source_code=None,
|
|
created_at=datetime.utcnow(),
|
|
updated_at=datetime.utcnow(),
|
|
)
|
|
)
|
|
except SQLAlchemyError as e:
|
|
await session.rollback()
|
|
raise RuntimeError(f"Ошибка при импорте пользователя tg_id={tg_id}") from e
|
|
|
|
key_exists = await session.execute(select(Key).where(Key.client_id == client_id))
|
|
if key_exists.scalar():
|
|
skipped += 1
|
|
continue
|
|
|
|
try:
|
|
session.add(
|
|
Key(
|
|
tg_id=tg_id,
|
|
client_id=client_id,
|
|
email=email,
|
|
created_at=created_at,
|
|
expiry_time=expiry_time,
|
|
key="",
|
|
server_id=server_id,
|
|
remnawave_link=None,
|
|
tariff_id=None,
|
|
is_frozen=False,
|
|
alias=None,
|
|
notified=False,
|
|
notified_24h=False,
|
|
)
|
|
)
|
|
imported += 1
|
|
except SQLAlchemyError as e:
|
|
await session.rollback()
|
|
raise RuntimeError(f"Ошибка при импорте ключа client_id={client_id}") from e
|
|
|
|
await session.commit()
|
|
return imported, skipped
|