diff --git a/.gitignore b/.gitignore index 42be1ec0..0b7bcc7b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ /vpn_users.db /config.py /database.db +/bot_old.py +/bot_old_2.py diff --git a/auth.py b/auth.py index 607c0445..daa5f98d 100644 --- a/auth.py +++ b/auth.py @@ -62,4 +62,15 @@ def link(session, user_id: str): # Создание ссылки для подключения VLESS val = f"vless://{client_id}@{DOMEN}?type={tcp}&security={reality}&fp=chrome&pbk=ZIMoEnEd8-qMJkReVU5JxbiEj8CCSrvpm_ckvJ-46TE&sni=yahoo.com&sid=0fb4b595&spx=%2F&flow={flow}#VPN_F-{email}" - return val \ No newline at end of file + return val + +def get_statistics(session, tg_id: int): + # Пример URL для получения статистики + STATS_URL = f"https://vpn.pocomacho.ru:34268/solonet/panel/api/inbounds/stats/{tg_id}" + response = session.get(STATS_URL) + if response.status_code == 200: + stats = response.json() + # Форматирование статистики для отображения + return f"Загрузка: {stats['upload']} MB\nВывод: {stats['download']} MB" + else: + raise Exception(f"Ошибка при получении статистики: {response.status_code}, {response.text}") diff --git a/bot.py b/bot.py index 808c1df8..dba0985d 100644 --- a/bot.py +++ b/bot.py @@ -13,9 +13,9 @@ import uuid import aiosqlite - class Form(StatesGroup): waiting_for_key_name = State() + waiting_for_statistics = State() bot = Bot(token=API_TOKEN) storage = MemoryStorage() @@ -24,16 +24,32 @@ router = Router() @dp.message(Command("start")) async def start_command(message: Message): - button_create_key = InlineKeyboardButton(text='Создать ключ', callback_data='create_key') - keyboard = InlineKeyboardMarkup(inline_keyboard=[[button_create_key]]) + # Приветственное сообщение + welcome_text = "Добро пожаловать! Вы можете создать ключ для подключения VPN или просмотреть статистику использования." - await message.reply("Выберите действие:", reply_markup=keyboard) + # Кнопки для меню + button_create_key = InlineKeyboardButton(text='Создать ключ', callback_data='create_key') + button_view_stats = InlineKeyboardButton(text='Посмотреть статистику', callback_data='view_stats') + keyboard = InlineKeyboardMarkup(inline_keyboard=[[button_create_key], [button_view_stats]]) + + await message.reply(welcome_text, reply_markup=keyboard) @dp.callback_query(F.data == 'create_key') async def process_callback_create_key(callback_query: types.CallbackQuery, state: FSMContext): await callback_query.message.reply("Введите имя вашего профиля VPN:") await state.set_state(Form.waiting_for_key_name) + await callback_query.answer() +@dp.callback_query(F.data == 'view_stats') +async def process_callback_view_stats(callback_query: types.CallbackQuery, state: FSMContext): + tg_id = callback_query.from_user.id + # Функция для получения статистики (вы должны реализовать эту функцию в соответствующем модуле) + # statistics = get_statistics(tg_id) + + # Для примера + statistics = "Здесь будет ваша статистика" + + await callback_query.message.reply(f"Ваша статистика:\n{statistics}") await callback_query.answer() @dp.message() @@ -42,45 +58,49 @@ async def handle_text(message: types.Message, state: FSMContext): if current_state == Form.waiting_for_key_name.state: try: + tg_id = message.from_user.id + + # Проверка на наличие активного ключа + async with aiosqlite.connect(DATABASE_PATH) as db: + async with db.execute("SELECT COUNT(*) FROM connections WHERE tg_id = ? AND expiry_time > ?", (tg_id, int(datetime.utcnow().timestamp() * 1000))) as cursor: + count = await cursor.fetchone() + if count[0] > 0: + await message.reply("У вас уже есть активный ключ. Один клиент может иметь только один активный ключ.") + return + session = login_with_credentials(ADMIN_USERNAME, ADMIN_PASSWORD) - # Параметры клиента + # Создание уникального ID клиента + client_id = str(uuid.uuid4()) email = message.text - tg_id = message.from_user.id + limit_ip = 1 + total_gb = 0 + current_time = datetime.utcnow() + expiry_time = int((current_time + timedelta(days=30)).timestamp() * 1000) + enable = True + flow = "xtls-rprx-vision" - # Проверяем наличие активного ключа - async with aiosqlite.connect(DATABASE_PATH) as db: - async with db.execute(''' - SELECT * FROM connections - WHERE tg_id = ? AND expiry_time > ? - ''', (tg_id, int(datetime.utcnow().timestamp() * 1000))) as cursor: - existing_key = await cursor.fetchone() - - if existing_key: - await message.reply("У вас уже есть активный ключ. Вы не можете создать больше одного ключа.") - else: - # Генерация нового ключа - client_id = str(uuid.uuid4()) - limit_ip = 1 - total_gb = 0 - current_time = datetime.utcnow() - expiry_time = int((current_time + timedelta(days=30)).timestamp() * 1000) - enable = True - flow = "xtls-rprx-vision" + add_client(session, client_id, email, tg_id, limit_ip, total_gb, expiry_time, enable, flow) - # Добавление клиента (функция для создания клиента) - result = add_client(session, client_id, email, tg_id, limit_ip, total_gb, expiry_time, enable, flow) + # Получение ссылки на подключение + connection_link = link(session, email) - # Сохранение данных в базу данных - await add_connection(tg_id, client_id, email, expiry_time) + # Сохранение данных в базу данных + await add_connection(tg_id, client_id, email, expiry_time) - # Получение ссылки на подключение - connection_link = link(session, email) - - # Отправка ключа в виде цитаты - await message.reply(f"Ключ создан:\n
{connection_link}
", parse_mode="HTML") + # Отправка ключа в виде цитаты + await message.reply(f"Ключ создан:\n
{connection_link}
", parse_mode="HTML") # Сброс состояния await state.clear() except Exception as e: - await message.reply(f"Произошла ошибка: {e}") \ No newline at end of file + await message.reply(f"Ошибка: {e}") + +# Запуск бота +async def main(): + dp.include_router(router) # Подключение роутера + await dp.start_polling(bot) # Запуск поллинга + +if __name__ == '__main__': + import asyncio + asyncio.run(main()) diff --git a/pic.png b/pic.png new file mode 100644 index 00000000..a6a548c5 Binary files /dev/null and b/pic.png differ