skip to Main Content

I’m developing a Telegram bot for a store using the aiogram library in Python. My project requires two bots, namely the store bot and the courier-delivery bot for the store, to work together in the same application. I’ve tried various approaches, but I believe the best solution for this is to use webhooks.

I tried to write my own server so that it would send an update to the right bot.

from aiogram import Bot, Dispatcher, types
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiohttp import web
from datetime import datetime
import courier
import registration
import shop
import time
import config
import middlewares

users_notified = {}
start_time = datetime.fromtimestamp(time.time())

dp = Dispatcher(config.bot, storage=MemoryStorage()) #User bot
dpc = Dispatcher(config.bot_courier, storage=MemoryStorage()) #Courier Bot


dp.middleware.setup(middlewares.AntiSpamMiddleware())
dp.middleware.setup(middlewares.OnlineTimeMiddleWare())
registration.BindRegistration(dp)
shop.BindShop(dp)

# Бот курьера
dpc = Dispatcher(config.bot_courier, storage=MemoryStorage())
courier.BindCourier(dpc)

# Create aiohttp application
app = web.Application()


async def on_startup(app):
    await config.bot.set_webhook(config.WEBHOOK_URL, drop_pending_updates=False)
    await config.bot_courier.set_webhook(config.WEBHOOK_URL_COURIER, drop_pending_updates=False)

async def on_shutdown(app):
    await config.bot.delete_webhook()
    session1 = await config.bot.get_session()
    await session1.close()

    await config.bot_courier.delete_webhook()
    session2 = await config.bot_courier.get_session()
    await session2.close()
async def process_update1(request):
    data = await request.json()
    update = types.Update(**data)

    if update.message.date < start_time:
        user_id = update.message.from_user.id
        if user_id not in users_notified and config.notify:
            await config.bot.send_message(user_id, "There was an error, but we are back online.")
            users_notified[user_id] = True  # Mark the user as notified
        return web.Response()

    Bot.set_current(config.bot)
    await dp.process_update(update)
    return web.Response()
async def process_update2(request):
    data = await request.json()
    update = types.Update(**data)

    # Ignore updates that were sent before the server was started
    if update.message.date < start_time:
        return web.Response()

    Bot.set_current(config.bot_courier)
    await dpc.process_update(update)
    return web.Response()


app.on_startup.append(on_startup)
app.on_shutdown.append(on_shutdown)

app.router.add_post(config.WEBHOOK_PATH, process_update1)
app.router.add_post(config.WEBHOOK_PATH_COURIER, process_update2)

web.run_app(app, host='0.0.0.0', port=3000)

But I am getting error "state = Dispatcher.get_current().current_state()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: ‘NoneType’ object has no attribute ‘current_state’", I get it the first time "get_current" is called, no matter where it first occurs.

Please help, explain what I’m doing wrong, maybe there are some others , more trivial approaches to solving this problem Thanks in advance!

I tried different ways to implement 2 bots in one project, tried using asyncio.gather(executor.start_webhook(),…) to run this as a caroutine. I also tried to use long-poolong but all this did not work correctly.

2

Answers


  1. For me, using aiogram 2.17.1 and a long-polling looks like this:
    in Initializer created 2 Bot and 2 Dispatcher objects

    async def start() -> None:
        initializer = Initializer()
        await asyncio.gather(initializer.dp.start_polling(), initializer.admin_dp.start_polling())
    
    
    if __name__ == '__main__':
        loop = asyncio.get_event_loop()
        loop.run_until_complete(start())
    
    Login or Signup to reply.
  2. I know its quite late but i fixed it like this:

    import asyncio
    
    async def start_raid_bot():
        dp_bot1 = Dispatcher()
        dp_bot1.include_router(raid_router)
        await dp_bot1.start_polling(bot1)
    
    async def start_trend_bot():
        dp_bot2 = Dispatcher()
        dp_bot2.include_router(router_trend_bot)
        await dp_bot2.start_polling(bot2)
    
    async def main():
        asyncio.create_task(confirm_payment_and_inform_user())
        task_bot1 = asyncio.create_task(start_raid_bot())
        task_bot2 = asyncio.create_task(start_trend_bot())
        await task_bot1
        await task_bot2
    
    if __name__ == "__main__":
        asyncio.run(main())
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search