Урок 8.3 — Интеграция с pyTelegramBotAPI
Учимся интегрировать aiosend с pyTelegramBotAPI (telebot) — синхронной библиотекой для создания Telegram-ботов.
pyTelegramBotAPI (telebot) — популярная синхронная библиотека для Telegram-ботов. Так как aiosend — асинхронная библиотека, интеграция требует запуска aiosend в отдельном потоке или использования SyncCryptoPay. В этом уроке мы рассмотрим оба подхода.
Подход 1: aiosend в отдельном потоке
Самый надёжный способ — запустить aiosend polling в отдельном потоке, так как pyTelegramBotAPI блокирует основной поток своим bot.infinity_polling().
import asyncio
import threading
import telebot
from aiosend import CryptoPay
BOT_TOKEN = "123456:ABCdefGHIjklmNOP"
CP_TOKEN = "1234:ABCDefGHIJklmnOPQRST"
bot = telebot.TeleBot(BOT_TOKEN)
cp = CryptoPay(token=CP_TOKEN)
@bot.message_handler(commands=["start"])
def start(message):
bot.reply_to(message, "Привет! Используй /pay 10 USDT")
@bot.message_handler(commands=["pay"])
def pay(message):
args = message.text.split()[1:]
if len(args) < 2:
bot.reply_to(message, "Пример: /pay 10 USDT")
return
amount, asset = float(args[0]), args[1].upper()
# Создаём инвойс (синхронный вызов)
invoice = cp.create_invoice(
amount=amount,
asset=asset,
payload=str(message.from_user.id),
)
bot.reply_to(
message,
f"🧾 Счёт на {amount} {asset}:\n"
f"{invoice.bot_invoice_url}",
)
@cp.invoice_paid()
async def on_paid(invoice):
"""Асинхронный хендлер оплаты."""
user_id = int(invoice.payload)
bot.send_message(
user_id,
f"✅ Оплата {invoice.amount} {invoice.asset} получена!",
)
def run_aiosend():
"""Запускает aiosend polling в отдельном потоке."""
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(cp.start_polling())
if __name__ == "__main__":
# Запускаем aiosend в фоновом потоке
threading.Thread(target=run_aiosend, daemon=True).start()
# Запускаем бота (блокирует основной поток)
print("Бот запущен...")
bot.infinity_polling()
💡 Как это работает?
Создаётся отдельный поток, в котором запускается event loop с aiosend polling. pyTelegramBotAPI работает в основном потоке. Оба потока не блокируют друг друга. Обрати внимание: cp.create_invoice() вызывается без await, так как aiosend поддерживает синхронный режим вызовов.
Ожидание оплаты через invoice.poll()
В синхронном контексте invoice.poll() тоже можно вызвать синхронно. Он заблокирует поток до оплаты или таймаута.
@bot.message_handler(commands=["buy"])
def buy(message):
invoice = cp.create_invoice(
amount=15,
asset="USDT",
description="Премиум",
payload=str(message.from_user.id),
)
msg = bot.send_message(
message.chat.id,
f"💳 Счёт на 15 USDT\n{invoice.bot_invoice_url}\n\n⏳ Ожидаем...",
)
try:
# Синхронный poll — блокирует поток до оплаты
paid = invoice.poll()
bot.edit_message_text(
f"✅ Оплачено: {paid.paid_amount} {paid.paid_asset}",
message.chat.id,
msg.message_id,
)
except Exception as e:
bot.edit_message_text(
f"❌ Ошибка: {e}",
message.chat.id,
msg.message_id,
)
⚠️ Важно: блокировка потока
Синхронный invoice.poll() блокирует поток до оплаты или таймаута. В это время бот не сможет отвечать на другие сообщения. Используй этот подход только если оплата ожидается быстро (1-2 минуты). Для длительного ожидания лучше использовать глобальный хендлер @cp.invoice_paid().
Полный пример: магазин на pyTelegramBotAPI
import asyncio
import threading
import telebot
from telebot import types
from aiosend import CryptoPay
BOT_TOKEN = "123456:ABCdefGHIjklmNOP"
CP_TOKEN = "1234:ABCDefGHIJklmnOPQRST"
bot = telebot.TeleBot(BOT_TOKEN)
cp = CryptoPay(token=CP_TOKEN)
PRODUCTS = {
"premium": {"name": "Премиум", "price": 15, "asset": "USDT"},
"vip": {"name": "VIP", "price": 50, "asset": "USDT"},
}
@bot.message_handler(commands=["start"])
def start(message):
markup = types.InlineKeyboardMarkup()
markup.add(
types.InlineKeyboardButton(
"💎 Премиум", callback_data="buy_premium"
),
types.InlineKeyboardButton(
"⭐ VIP", callback_data="buy_vip"
),
)
bot.send_message(
message.chat.id,
"🛒 Добро пожаловать в магазин!",
reply_markup=markup,
)
@bot.callback_query_handler(func=lambda c: c.data.startswith("buy_"))
def handle_buy(callback):
product_key = callback.data.replace("buy_", "")
product = PRODUCTS.get(product_key)
if not product:
bot.answer_callback_query(callback.id, "Товар не найден")
return
invoice = cp.create_invoice(
amount=product["price"],
asset=product["asset"],
description=product["name"],
payload=f"{callback.from_user.id}:{product_key}",
)
bot.answer_callback_query(callback.id, "Счёт создан!")
bot.send_message(
callback.message.chat.id,
f"💳 {product['name']}\n"
f"Сумма: {product['price']} {product['asset']}\n"
f"{invoice.bot_invoice_url}\n\n"
f"Ожидаем оплату...",
)
@bot.message_handler(commands=["buy"])
def buy_direct(message):
"""Быстрая покупка с ожиданием."""
invoice = cp.create_invoice(
amount=10, asset="USDT",
payload=str(message.from_user.id),
)
msg = bot.send_message(
message.chat.id,
f"🧾 Счёт: {invoice.bot_invoice_url}"
)
try:
paid = invoice.poll()
bot.edit_message_text(
f"✅ Оплачено: {paid.paid_amount} {paid.paid_asset}",
message.chat.id,
msg.message_id,
)
except Exception as e:
bot.edit_message_text(
f"❌ {e}", message.chat.id, msg.message_id,
)
@cp.invoice_paid()
async def on_paid(invoice):
"""Глобальный хендлер оплаты."""
user_id, product_key = (invoice.payload or ":").split(":")
product = PRODUCTS.get(product_key, {"name": "товар"})
bot.send_message(
int(user_id),
f"✅ {product['name']} оплачен и активирован!",
)
print(f"Платёж: user={user_id} product={product['name']}")
def run_aiosend():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(cp.start_polling())
if __name__ == "__main__":
threading.Thread(target=run_aiosend, daemon=True).start()
print("Бот запущен...")
bot.infinity_polling()
🔍 Ключевые моменты
- aiosend запускается в отдельном потоке через
threading.Thread - Синхронные вызовы aiosend (
cp.create_invoice) работают без await - Глобальный хендлер
@cp.invoice_paid()асинхронный, но может вызывать синхронный bot.send_message bot.edit_message_textиспользует синтаксис с chat_id и message_id- pyTelegramBotAPI использует
bot.infinity_polling()для запуска
Что важно запомнить
Практическое задание
Задание: Donate-бот на pyTelegramBotAPI
Создай бота на pyTelegramBotAPI + aiosend, который:
- По команде /donate создаёт инвойс на 5 USDT
- Отправляет ссылку пользователю
- Обрабатывает оплату через @cp.invoice_paid()
- Благодарит пользователя
- Запускает aiosend в отдельном потоке
Подсказка:
import asyncio, threading
import telebot
from aiosend import CryptoPay
bot = telebot.TeleBot("BOT_TOKEN")
cp = CryptoPay(token="CP_TOKEN")
@bot.message_handler(commands=["donate"])
def donate(message):
invoice = cp.create_invoice(
amount=5, asset="USDT",
payload=str(message.from_user.id),
)
bot.send_message(
message.chat.id,
f"💛 Счёт на 5 USDT\n{invoice.bot_invoice_url}"
)
@cp.invoice_paid()
async def on_paid(invoice):
bot.send_message(
int(invoice.payload),
"❤️ Спасибо за донат!"
)
def run_aiosend():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(cp.start_polling())
threading.Thread(target=run_aiosend, daemon=True).start()
bot.infinity_polling()
Урок 8.3: Интеграция с pyTelegramBotAPI
5 вопросов