I have a problem with Telethon. I have a NewMessage() event listener, and it works just fine. But when exit the script with CTRL + C and start it again, it does not connect to the chat again.
I have to manually delete the connection in the Telegram app.
My question is:
How can I force the client to disconnect, when I press CTRL + C or when the program is closed.
from telethon import TelegramClient, events, sync
import globals, asyncio
client = TelegramClient('anon',
globals.api_id, globals.api_hash)
#client.on(events.NewMessage(chats=globals.tLink))
async def my_event_handler(event):
print(event.raw_text)
client.start()
client.run_until_disconnected()
If you need to repeatedly restart the script, it might be reasonable to not create a separate/new session for every run. Try using None to not create a .session file, instead of creating an anon.session.
client = TelegramClient(None, globals.api_id, globals.api_hash)
This is how I do it:
async def enviar():
(code)
async def main():
global ME
ME = await info_me();
enviar_var = asyncio.create_task(enviar());
await enviar_var;
with client:
try:
client.loop.run_until_complete(main());
except:
print("Encerrando...");
future = asyncio.Future();
future.set_result("1");
con.close();#I am using a SQLite database, you can ignore this line
print("Adeus!");
Related
I understand that usually the discord bots are in a listening (blocking) loop, but how can I create a function that connects, send a message or perform any action and disconnect in a non blocking flow?
I'm using discord.py and I'm looking for something like:
import discord
TOKEN = "mYtOkEn"
discord.connect(TOKEN)
discord.send("I'm sending this message")
discord.disconnect()
I already tryied playing with the async but have problems with the threading, so was wondering if there is something more simple.
It is for a button that when clicked, perform that action but after that it can continue working on other tasks
Thanks beforehand
One way you could accomplish this is by using a custom event loop.
Example:
import discord
import asyncio
from threading import Thread
TOKEN = "secret"
client = discord.Client()
def init():
loop = asyncio.get_event_loop()
loop.create_task(client.start(TOKEN))
Thread(target=loop.run_forever).start()
#client.event
async def on_message(message):
if message.author == client.user:
return
await message.channel.send('Hello!')
#client.event
async def on_ready():
print("Discord bot logged in as: %s, %s" % (client.user.name, client.user.id))
init()
print("Non-blocking")
Take a look at this for more info: C-Python asyncio: running discord.py in a thread
Thank you for your help and support. With the SleepyStew answer I could find the path to solve it and went this way:
import discord
import asyncio
def discord_single_task():
# Define Coroutine
async def coroutine_to_run():
TOKEN = "Secret"
# Instantiate the Client Class
client = discord.Client()
# # Start (We won't use connect because we don't want to open a websocket, it will start a blocking loop and it is what we are avoiding)
await client.login(TOKEN)
# Do what you have to do
print("We are doing what we want to do")
# Close
await client.close()
# Create Loop to run coroutine
loop = asyncio.new_event_loop()
llll = loop.create_task(coroutine_to_run())
loop.run_until_complete(llll)
return 'Action performed successfully without a blocking loop!'
i am using Pyrogram to work with telegram API.
I have succeed to join channel.
I have a task to add message handler and receive messages in channel.
But the message handler is not invoked when message arrives (i am the owner of channel)
The code:
import asyncio
from pyrogram import Client
import time
from pyrogram.handlers import MessageHandler, RawUpdateHandler
api_id = "xx"
api_hash = "xx"
def my_handler(client, message):
message.forward("me")
print('sent msg')
async def main():
async with Client("my_account", api_id, api_hash) as app:
a = await app.get_chat('test2k3')
msg_handler = MessageHandler(my_handler)
app.add_handler(msg_handler)
await app.join_chat(str(a.id))
print(f'joined chat ' + str(a.id))
while True:
time.sleep(2.4)
asyncio.get_event_loop().run_until_complete(main())
Sleeping while the client runs halts it until the sleep is over. Pyrogram itself will already keep itself alive until Ctrl and C is pressed. Remove your while True sleep loop.
as recommended by sudden_appearance
use asyncio.sleep() inside async functions instead of time.sleep()
In discord.py, you can initialize a Client, and run it with client.run(). But the function never returns.
What if I just want to just retrieve some message history then use it in jupyter notebook?
#bot.command()
async def history(ctx):
counter = 0
messageList=[]
async for message in ctx.channel.history(limit = 100):
print(message.author, message.content)
counter += 1
messageList.append(message)
await ctx.send(f'total **{counter}** messages in this channel.')
# How to return the messageList to my jupyter notebook cell and I start playing with the messageList?
How to return the messageList?
There isn't a good way to do this. discord.py is designed to be started once and run until your program terminates since all of the internal objects are destroyed upon closure of the bot, which makes starting the bot back up again nearly impossible. And it is not possible to "pause" discord.py and run your code then resumes discord.py afterwards, because Discord API communicates via web sockets, which relies on a constant stream of heartbeats and acks.
A possible workaround would be to:
Use a single event loop through out the code.
Use loop.run_until_complete() to start the bot's internal loop.
Create a new Client every time you need to run the bot.
Create an on_ready event handle that fetches the information.
Downside is that you won't be able to interact with the Message objects (ie. delete, edit, etc), they will be view only.
Example:
import asyncio
import discord
TOKEN = "YOURBOTTOKEN"
loop = asyncio.get_event_loop()
def get_message_list(token, channel_id):
client = discord.Client(loop=loop)
message_list = []
#client.event
async def on_ready():
nonlocal message_list
channel = client.get_channel(channel_id)
if not channel: # incase the channel cache isn't fully populated yet
channel = await client.fetch_channel(channel_id)
async for message in channel.history(limit=100):
message_list.append(message)
await client.close()
async def runner():
try:
await client.start(token)
finally:
if not client.is_closed():
# Incase the bot was terminated abruptly (ie. KeyboardInterrupt)
await client.close()
loop.run_until_complete(runner())
return message_list
message_list = get_message_list(TOKEN, channel_id=747699344911712345)
print("Message list for channel #1:", message_list)
# ... do stuff with message_list
message_list = get_message_list(TOKEN, channel_id=747699344911754321)
print("Message list for channel #2:", message_list)
# ... do more stuff with message_list
# Finally closes the event loop when everything's done
loop.close()
Instead of doing this, I'd recommend you to find another solution to the task you're trying to accomplish.
I'm new to websockets and asyncio and I'm trying to get a simple example working. I would like to create a server that accepts connections from multiple clients and concurrently runs a loop that sends a message to every connection once a second. I'm also trying to use asyncio.run() which I believe is preferred to the get_event_loop() code on which many examples are based.
Here's my code so far:
import asyncio
import websockets
USERS = set()
async def register(websocket, path):
USERS.add(websocket)
await websocket.send("Successfully registered")
async def count():
count = 0
while True:
print(f"Iteration: {count}")
if USERS:
for user in USERS:
await user.send("Sending message back to client")
await asyncio.sleep(1)
count +=1
async def serve():
server = await websockets.serve(register, 'localhost', 8765)
await server.wait_closed()
print("Server closed")
async def main():
await asyncio.gather(count(), serve())
asyncio.run(main())
When I run this the count coroutine works until I make a connection from a client. At this point the connection is successfully registered but when I try to send a message back to the client in count() I get an error because the connection is already closed. How should I change my code to stop this from happening?
How should I change my code to stop this from happening?
The problem might be that your handler, the register coroutine, is returning immediately, which prompts websockets to close the connection. Try to change it like this:
async def register(websocket, path):
USERS.add(websocket)
await websocket.send("Successfully registered")
await asyncio.Event().wait()
If that helps, you can put the event in USERS along with websocket, so that you have a way to terminate the connection to the client when you want to.
In Python, I'm using "websockets" library for websocket client.
import asyncio
import websockets
async def init_sma_ws():
uri = "wss://echo.websocket.org/"
async with websockets.connect(uri) as websocket:
name = input("What's your name? ")
await websocket.send('name')
greeting = await websocket.recv()
The problem is the client websocket connection is disconnected once a response is received. I want the connection to remain open so that I can send and receive messages later.
What changes do I need to keep the websocket open and be able to send and receive messages later?
I think your websocket is disconnected due to exit from context manager after recv().
Such code works perfectly:
import asyncio
import websockets
async def init_sma_ws():
uri = "wss://echo.websocket.org/"
async with websockets.connect(uri) as websocket:
while True:
name = input("What's your name? ")
if name == 'exit':
break
await websocket.send(name)
print('Response:', await websocket.recv())
asyncio.run(init_sma_ws())
In your approach you used a asynchronous context manager which closes a connection when code in the block is executed. In the example below an infinite asynchronous iterator is used which keeps the connection open.
import asyncio
import websockets
async def main():
async for websocket in websockets.connect(...):
try:
...
except websockets.ConnectionClosed:
continue
asyncio.run(main())
More info in library's docs.