aiogram/examples/webhook_example.py

200 lines
6.5 KiB
Python
Raw Normal View History

"""
Example outdated
"""
2017-08-15 00:08:56 +03:00
import asyncio
import ssl
import sys
from aiohttp import web
import aiogram
from aiogram import Bot, types
2017-08-15 00:08:56 +03:00
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import Dispatcher
from aiogram.dispatcher.webhook import get_new_configured_app, SendMessage
from aiogram.types import ChatType, ParseMode, ContentTypes
2017-08-15 00:08:56 +03:00
from aiogram.utils.markdown import hbold, bold, text, link
2019-06-29 19:53:18 +03:00
TOKEN = "BOT TOKEN HERE"
2017-08-15 00:08:56 +03:00
2019-06-29 19:53:18 +03:00
WEBHOOK_HOST = "example.com" # Domain name or IP addres which your bot is located.
2017-08-15 00:08:56 +03:00
WEBHOOK_PORT = 443 # Telegram Bot API allows only for usage next ports: 443, 80, 88 or 8443
2019-06-29 19:53:18 +03:00
WEBHOOK_URL_PATH = "/webhook" # Part of URL
2017-08-15 00:08:56 +03:00
# This options needed if you use self-signed SSL certificate
# Instructions: https://core.telegram.org/bots/self-signed
2019-06-29 19:53:18 +03:00
WEBHOOK_SSL_CERT = "./webhook_cert.pem" # Path to the ssl certificate
WEBHOOK_SSL_PRIV = "./webhook_pkey.pem" # Path to the ssl private key
2017-08-15 00:08:56 +03:00
WEBHOOK_URL = f"https://{WEBHOOK_HOST}:{WEBHOOK_PORT}{WEBHOOK_URL_PATH}"
2018-03-18 14:41:34 +03:00
# Web app settings:
# Use LAN address to listen webhooks
# User any available port in range from 1024 to 49151 if you're using proxy, or WEBHOOK_PORT if you're using direct webhook handling
2019-06-29 19:53:18 +03:00
WEBAPP_HOST = "localhost"
2018-03-18 14:41:34 +03:00
WEBAPP_PORT = 3001
2019-06-29 19:53:18 +03:00
BAD_CONTENT = (
ContentTypes.PHOTO & ContentTypes.DOCUMENT & ContentTypes.STICKER & ContentTypes.AUDIO
)
2017-08-15 00:08:56 +03:00
loop = asyncio.get_event_loop()
bot = Bot(TOKEN, loop=loop)
storage = MemoryStorage()
dp = Dispatcher(bot, storage=storage)
async def cmd_start(message: types.Message):
2018-02-21 19:09:44 +03:00
# Yep. aiogram allows to respond into webhook.
2017-08-15 00:08:56 +03:00
# https://core.telegram.org/bots/api#making-requests-when-getting-updates
2019-06-29 19:53:18 +03:00
return SendMessage(
chat_id=message.chat.id, text="Hi from webhook!", reply_to_message_id=message.message_id
)
2017-08-15 00:08:56 +03:00
async def cmd_about(message: types.Message):
2018-02-21 19:09:44 +03:00
# In this function markdown utils are userd for formatting message text
2019-06-29 19:53:18 +03:00
return SendMessage(
message.chat.id,
text(
bold("Hi! I'm just a simple telegram bot."),
"",
text("I'm powered by", bold("Python", Version(*sys.version_info[:]))),
text(
"With",
link(text("aiogram", aiogram.VERSION), "https://github.com/aiogram/aiogram"),
),
sep="\n",
),
parse_mode=ParseMode.MARKDOWN,
)
2017-08-15 00:08:56 +03:00
async def cancel(message: types.Message):
# Get current state context
state = dp.current_state(chat=message.chat.id, user=message.from_user.id)
2018-02-21 19:09:44 +03:00
# If current user in any state - cancel it.
2017-08-15 00:08:56 +03:00
if await state.get_state() is not None:
await state.set_state(state=None)
2019-06-29 19:53:18 +03:00
return SendMessage(message.chat.id, "Current action is canceled.")
2017-08-15 00:08:56 +03:00
# Otherwise do nothing
async def unknown(message: types.Message):
"""
Handler for unknown messages.
"""
2019-06-29 19:53:18 +03:00
return SendMessage(
message.chat.id,
f"I don't know what to do with content type `{message.content_type()}`. Sorry :c",
)
2017-08-15 00:08:56 +03:00
async def cmd_id(message: types.Message):
"""
Return info about user.
"""
if message.reply_to_message:
target = message.reply_to_message.from_user
chat = message.chat
elif message.forward_from and message.chat.type == ChatType.PRIVATE:
target = message.forward_from
chat = message.forward_from or message.chat
else:
target = message.from_user
chat = message.chat
2019-06-29 19:53:18 +03:00
result_msg = [hbold("Info about user:"), f"First name: {target.first_name}"]
2017-08-15 00:08:56 +03:00
if target.last_name:
result_msg.append(f"Last name: {target.last_name}")
if target.username:
result_msg.append(f"Username: {target.mention}")
result_msg.append(f"User ID: {target.id}")
2017-08-15 00:08:56 +03:00
2019-06-29 19:53:18 +03:00
result_msg.extend([hbold("Chat:"), f"Type: {chat.type}", f"Chat ID: {chat.id}"])
2017-08-15 00:08:56 +03:00
if chat.type != ChatType.PRIVATE:
result_msg.append(f"Title: {chat.title}")
else:
result_msg.append(f"Title: {chat.full_name}")
2019-06-29 19:53:18 +03:00
return SendMessage(
message.chat.id,
"\n".join(result_msg),
reply_to_message_id=message.message_id,
parse_mode=ParseMode.HTML,
)
2017-08-15 00:08:56 +03:00
async def on_startup(app):
2018-02-21 19:09:44 +03:00
# Demonstrate one of the available methods for registering handlers
2017-08-15 00:08:56 +03:00
# This command available only in main state (state=None)
2019-06-29 19:53:18 +03:00
dp.register_message_handler(cmd_start, commands=["start"])
2017-08-15 00:08:56 +03:00
2018-02-21 19:09:44 +03:00
# This handler is available in all states at any time.
2019-06-29 19:53:18 +03:00
dp.register_message_handler(cmd_about, commands=["help", "about"], state="*")
dp.register_message_handler(
unknown,
content_types=BAD_CONTENT,
func=lambda message: message.chat.type == ChatType.PRIVATE,
)
2017-08-15 00:08:56 +03:00
2018-02-21 19:09:44 +03:00
# You are able to register one function handler for multiple conditions
2019-06-29 19:53:18 +03:00
dp.register_message_handler(cancel, commands=["cancel"], state="*")
dp.register_message_handler(
cancel, func=lambda message: message.text.lower().strip() in ["cancel"], state="*"
)
dp.register_message_handler(cmd_id, commands=["id"], state="*")
dp.register_message_handler(
cmd_id,
func=lambda message: message.forward_from
or message.reply_to_message
and message.chat.type == ChatType.PRIVATE,
state="*",
)
2017-08-15 00:08:56 +03:00
# Get current webhook status
webhook = await bot.get_webhook_info()
# If URL is bad
if webhook.url != WEBHOOK_URL:
2018-02-21 19:09:44 +03:00
# If URL doesnt match current - remove webhook
2017-08-15 00:08:56 +03:00
if not webhook.url:
await bot.delete_webhook()
# Set new URL for webhook
2019-06-29 19:53:18 +03:00
await bot.set_webhook(WEBHOOK_URL, certificate=open(WEBHOOK_SSL_CERT, "rb"))
2018-02-21 19:09:44 +03:00
# If you want to use free certificate signed by LetsEncrypt you need to set only URL without sending certificate.
2017-08-15 00:08:56 +03:00
async def on_shutdown(app):
"""
2018-02-21 19:09:44 +03:00
Graceful shutdown. This method is recommended by aiohttp docs.
2017-08-15 00:08:56 +03:00
"""
# Remove webhook.
await bot.delete_webhook()
# Close Redis connection.
2017-10-18 22:32:21 +03:00
await dp.storage.close()
2017-08-15 00:08:56 +03:00
await dp.storage.wait_closed()
2019-06-29 19:53:18 +03:00
if __name__ == "__main__":
2017-08-15 00:08:56 +03:00
# Get instance of :class:`aiohttp.web.Application` with configured router.
app = get_new_configured_app(dispatcher=dp, path=WEBHOOK_URL_PATH)
# Setup event handlers.
app.on_startup.append(on_startup)
app.on_shutdown.append(on_shutdown)
# Generate SSL context
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.load_cert_chain(WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV)
# Start web-application.
2018-03-18 14:41:34 +03:00
web.run_app(app, host=WEBAPP_HOST, port=WEBAPP_PORT, ssl_context=context)
2017-08-15 00:08:56 +03:00
# Note:
2018-02-21 19:09:44 +03:00
# If you start your bot using nginx or Apache web server, SSL context is not required.
# Otherwise you need to set `ssl_context` parameter.