Telethon, How can I receive and send messages in parallel? (how to run events in parallel)

Viewed 363

I'm trying to run a Telegram client that is capable of sending and receiving messages in parallel, however, I want to use the "event" option, because I think it's more efficient than sending requests for the history of the chat all the time.

The problem is that the "receber" (receiver) function, seem to only star after the "enviar" (sending) function finishs, that is not what I want.

Is there any way to solve this? Anything in the documentation (note: yes, I have checked it, but I couldn't find anything about using events and non-event functions at the same time) will be useful.

from variables import api_id, api_hash
from telethon import TelegramClient, events, utils
import asyncio
import logging
logging.basicConfig(format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s',
                    level=logging.WARNING)

client = TelegramClient('anon', api_id, api_hash);

lock = asyncio.Lock();

async def info_me():
    me = await client.get_me();
    return me;

async def enviar():
    while True:
        try:
            await lock.acquire();
            try:
                msg_txt = open("msg.txt", "r");
                updates = msg_txt.read();
                msg_txt.close();

            finally:
                lock.release();
            
            print("==================");
            print(updates);
            print("==================");
            msg = input("Enviar: ");
            if msg != "//":
                msg = msg.split(" | ");
                await client.send_message(msg[0], msg[1]);

            else:
                await asyncio.sleep(0.1);
            

        except(KeyboardInterrupt):
            print("Adeus!");
            break;

        except Exception as e:
            print("\n======ERRO======\n");
            print(e);
            break;
        
async def receber(event):
    try:
        sender = await event.get_sender();
        name = utils.get_display_name(sender);
        message = name + "::::::" + event.text + "\n"; #<--proteger contra input do usuário
        await lock.acquire();
        try:
            file = open('msg.txt', '+a');
            file.write(message);
            file.close();

        finally:
            lock.release()

    except(KeyboardInterrupt):
        print("Adeus!");

    except("Cannot send requests while disconnected"):
        print("Adeus!");

    except Exception as e:
        print("\n======ERRO======\n");
        print(e);
    
client.add_event_handler(receber, events.NewMessage)
async def main():
    me = await info_me(); #pegando informação sobre a conexão, caso eu precise
    
    enviar_var = asyncio.create_task(enviar());

    await enviar_var;
        
with client:
    client.loop.run_until_complete(main());

1 Answers

So, I have found this example on the telethons github. There, you can find this function:

# Create a global variable to hold the loop we will be using
loop = asyncio.get_event_loop()

(...other code...)

async def async_input(prompt):
    """

This is enough to make run in parallel. You can look the actual code to understand better! 
NOTE: If you only copy and paste this code, it will run, but there will be a error at the end. Any further comment is welcome! 
    Python's "input()" is blocking, which means the event loop we set
    above can't be running while we're blocking there. This method will
    let the loop run while we wait for input.
    """
    print(prompt, end='', flush=True)
    return (await loop.run_in_executor(None, sys.stdin.readline)).rstrip()

You should look to the documentation to understand better. Any further comment is welcome!

Related