Problem with synchronous command execution

73 views Asked by At

here is a code example:

import vk_api
from vk_api.longpoll import VkEventType, VkLongPoll
import discord
from discord.ext import commands
import asyncio

client = commands.Bot(command_prefix='!', intents=discord.Intents.all())

@client.event
async def on_ready():
    print('The bot is connected to Discord!')

@client.event
async def on_message(message):
    if message.author == client.user:  
        return
    await client.process_commands(message)

@client.command(pass_context=True)
async def hi(ctx: commands.Context):
    await ctx.send('Hi!')

login = 'login'
password = 'password'
api_version = 'api'
chat_id = 1

vk_session = vk_api.VkApi(login, password, app_id=api_version)
vk_session.auth()

vk = vk_session.get_api()

longpoll = VkLongPoll(vk_session)
async def disbot():
    for event in longpoll.listen():
        if event.type == VkEventType.MESSAGE_NEW and event.from_chat and event.chat_id == chat_id:
            user_id = event.user_id
            message = event.text
            attachments = event.attachments
            user_info = vk.users.get(user_ids=user_id)
            user_name = user_info[0]['first_name'] + ' ' + user_info[0]['last_name']
            await client.wait_until_ready()
            channel = client.get_channel(id)
            if '@all' in message:
                if 'attach1_type' in attachments:
                    await channel.send(f"{user_name} » {message} [Attachment] @everyone")
                else:
                    await channel.send(f"{user_name} » {message} @everyone")
            else:
                if 'attach1_type' in attachments:
                    await channel.send(f"{user_name} » {message} [Attachment]")
                else:
                    await channel.send(f"{user_name} » {message}")

async def main():
    async with client:
        client.loop.create_task(disbot())
        await client.start('Token')

asyncio.run(main())

I created a discord bot that forwards messages from VK chat to discord, and decided to add several commands to it. The problem is that when I run the bot, it only forwards messages, ignoring any commands.

I forced the bot to respond to commands, but then it does not forward messages. I will be glad if they tell me how to make the bot do everything at once.

1

There are 1 answers

0
Trevor On

You have discovered the annoyance of blocking code in an async program. The line, for event in longpoll.listen(): is blocking your event loop - it does not let any of your other code run.

Blocking code is blocking code, even if you put it in a task, so your best option is to find an async vk_api library replacement that uses async principals, a quick Google search revealed this one. Replacing your current functions with said async library could look like this:

import vkreal
import asyncio
import discord
from discord.ext import commands

client = commands.Bot(command_prefix='!', intents=discord.Intents.all())

# ... command definitions here

token = "Your token"
session = vkreal.VkApi(token = token)
vk = session.api_context()
longpoll = vkreal.VkLongPoll(session, loop = loop)

async def longpoll_listener():
    async for event in longpoll.listen():
        print(event['type']) 
        ... # Remaining code here

async def main():
    async with client:
        client.loop.create_task(longpoll_listener())
        await client.start('[BOT TOKEN]')

asyncio.run(main())

The code for this example was found in the vkreal repo tests, I recommend you check out its source code and documentation for how you can finish your implementation. Best of luck!