how to run pyrogram userbot with multiple user accounts using thread - python-3.x

I am coding a userbot in pyrogram but I want to run multiple Clients with different telegram account but I am stuck here.
I want to run userbot on multiple accounts using one script if I will run it separately then I have to host it so many time I want to host it for one time and run for every account I have.
I think this will help to understand what I am saying.
from pyrogram import Client, filters, handlers, idle
import threading
from pyrogram.handlers import MessageHandler
app1 = Client(
session, api_hash, api_id)
app2 = Client(session,
api_hash, api_id)
accounts = [app1, app2]
async def handlngmessage(client, message):
print(message)
print("\nstarted ")
await client.send_message("me", "recived")
def runner(c):
c.run()
for ac in accounts:
ac.add_handler(handlers.MessageHandler(unmutedtest))
t = threading.Thread(target=runner, args=(ac,))
t.start()
t.join()
When I run this I am just getting error
Output:
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python3.9/threading.py", line 954, in _bootstrap_inner
self.run()
File "/usr/lib/python3.9/threading.py", line 892, in run
self._target(*self._args, **self._kwargs)
File "/home/ak/Desktop/development/bots/pyrogramplugins/userbot/main.py", line 30, in runner
c.run()
File "/home/ak/.local/lib/python3.9/site-packages/pyrogram/methods/utilities/run.py", line 50, in run
loop = asyncio.get_event_loop()
File "/usr/lib/python3.9/asyncio/events.py", line 642, in get_event_loop
raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'Thread-1'.
Exception in thread Thread-2:
Traceback (most recent call last):
File "/usr/lib/python3.9/threading.py", line 954, in _bootstrap_inner
self.run()
File "/usr/lib/python3.9/threading.py", line 892, in run
self._target(*self._args, **self._kwargs)
File "/home/ak/Desktop/development/bots/pyrogramplugins/userbot/main.py", line 30, in runner
c.run()
File "/home/ak/.local/lib/python3.9/site-packages/pyrogram/methods/utilities/run.py", line 50, in run
loop = asyncio.get_event_loop()
File "/usr/lib/python3.9/asyncio/events.py", line 642, in get_event_loop
raise RuntimeError('There is no current event loop in thread %r.'
RuntimeError: There is no current event loop in thread 'Thread-2'.

With Pyrogram you don't need to use Threading. The internal code is already entirely asynchronous and you can just start the clients one after another, then call Client.idle() to keep them all "alive".
from pyrogram import Client
app1 = Client("first account")
app2 = Client("second account")
# You can either stack decorators ...
#app1.on_message()
#app2.on_message()
async def m_func(_, message):
pass
# ... or use multiple add_handler calls
app1.add_handler(MessageHandler(m_func))
app2.add_handler(MessageHandler(m_func))
# Then start all Clients and call idle() to keep them running
app1.start()
app2.start()
Client.idle()
app1.stop()
app2.stop()
Alternatively, here's a Gist with some more explanation.
https://gist.github.com/pokurt/96afa69e86725850b2101099461609ed

Related

how to gracefully close task loops in discord.py

I'm currently creating a discord bot that contains two task loops called check_members and check_music.
When a user enters the offline command, I'd like to gracefully stop these loops. I wrote this piece of code in my Cog class:
class MusicBot(commands.Cog):
# function called when bot is closing.
See [here](https://discordpy.readthedocs.io/en/stable/ext/commands/api.html?highlight=cog_unload#discord.ext.commands.Cog.cog_unload)
def cog_unload(self):
print("Debug")
self.check_members.cancel()
self.check_music.cancel()
print(self.check_members.is_running())
print(self.check_music.is_running())
# example of a task loop I have:
#tasks.loop(seconds=5)
async def check_members(self):
[code...]
In another script, I call the bot.close() function as follows:
await ctx.send("Going offline! See ya later.")
if self.voice is not None:
await self.disconnect()
await self.bot.close()
sys.exit(0)
When a user calls the offline command, that's what the bot prints out:
Debug
True
Task exception was never retrieved
future: <Task finished name='discord.py: on_message' coro=<Client._run_event() done, defined at /home/liuk23/.local/lib/python3.10/site-packages/discord/client.py:401> exception=SystemExit(0)>
Traceback (most recent call last):
File "/home/liuk23/Desktop/coding/Discord-bot-3/main.py", line 67, in <module>
loop.run_forever()
File "/usr/lib/python3.10/asyncio/base_events.py", line 600, in run_forever
self._run_once()
File "/usr/lib/python3.10/asyncio/base_events.py", line 1896, in _run_once
handle._run()
File "/usr/lib/python3.10/asyncio/events.py", line 80, in _run
self._context.run(self._callback, *self._args)
File "/home/liuk23/.local/lib/python3.10/site-packages/discord/client.py", line 409, in _run_event
await coro(*args, **kwargs)
File "/home/liuk23/.local/lib/python3.10/site-packages/discord/ext/commands/bot.py", line 1392, in on_message
await self.process_commands(message)
File "/home/liuk23/.local/lib/python3.10/site-packages/discord/ext/commands/bot.py", line 1389, in process_commands
await self.invoke(ctx) # type: ignore
File "/home/liuk23/.local/lib/python3.10/site-packages/discord/ext/commands/bot.py", line 1347, in invoke
await ctx.command.invoke(ctx)
File "/home/liuk23/.local/lib/python3.10/site-packages/discord/ext/commands/core.py", line 986, in invoke
await injected(*ctx.args, **ctx.kwargs) # type: ignore
File "/home/liuk23/.local/lib/python3.10/site-packages/discord/ext/commands/core.py", line 190, in wrapped
ret = await coro(*args, **kwargs)
File "/home/liuk23/Desktop/coding/Discord-bot-3/music.py", line 223, in offline
await self.functions.offline(ctx)
File "/home/liuk23/Desktop/coding/Discord-bot-3/funcitons.py", line 241, in offline
sys.exit(0)
SystemExit: 0
As you can notice, the Debug text gets printed out, so the cog_unload function get successfully called.
Although I am closing the loops, I get the Task was never retrieved error. Am I misunderstanding the error?
From sys.exit documentation:
Raise a SystemExit exception, signaling an intention to exit the interpreter.
What is happening is that the offline task, by throwing SystemExit, stops, but since no other task is awaiting on it, that exception is never retrieved.
The underlying problem is that, to quit the application, rather than throwing through sys.exit, it would be better to stop the running loop cleanly. For example, if the loop was run with loop.run_until_complete(some_future), it's necessary to set that future with some_future.set_result(some_result).
I fixed it by stopping the main loop that holds all the bot.
In my main script I instantiate the bot in the following manner:
try:
# loop runs until stop is called
loop.run_forever()
except KeyboardInterrupt:
pass
# finally block is called when loop is being stopped
finally:
# stop and close loop
loop.stop()
sys.exit(0)
By calling loop.stop() in another script, the finally block in main.py will be called and will successfully close the loop and the whole script.
Thanks to #Ulisse Bordignon for your answer

How to start websocket server in thread using python?

I want to start websocket server in separate thread. I have tried to implement as below but
getting Runtime error as it says attached to different loop
Code:
#!/usr/bin/env python
# WS server example
import asyncio
import websockets
import threading
import time
async def hello(websocket, path):
name = await websocket.recv()
print(name)
greeting = "Hello " + name +"!"
await websocket.send(greeting)
print(greeting)
start_server = websockets.serve(hello, "localhost", 8765)
eventLoop = asyncio.new_event_loop()
time.sleep(2)
def startWebSocket(loop, server):
print("WS: thread started")
asyncio.set_event_loop(eventLoop)
asyncio.get_event_loop().run_until_complete(start_server)
eventLoop.run_forever()
print("Run web socket in threaded env")
TH = threading.Thread(target=startWebSocket, args=[eventLoop, start_server,])
TH.start()
# then do some other work after this
Output:
Run web socket in threaded env
WS: thread started
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner
self.run()
File "/usr/lib/python3.5/threading.py", line 862, in run
self._target(*self._args, **self._kwargs)
File "threadWithWs.py", line 26, in startWebSocket
asyncio.get_event_loop().run_until_complete(start_server)
File "/usr/lib/python3.5/asyncio/base_events.py", line 387, in run_until_complete
return future.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 274, in result
raise self._exception
File "/usr/lib/python3.5/asyncio/tasks.py", line 241, in _step
result = coro.throw(exc)
File "/usr/lib/python3.5/asyncio/tasks.py", line 564, in _wrap_awaitable
return (yield from awaitable.__await__())
File "/home/krunal/.local/lib/python3.5/site-packages/websockets/py35/server.py", line 13, in __await_impl__
server = await self._creating_server
File "/usr/lib/python3.5/asyncio/base_events.py", line 923, in create_server
infos = yield from tasks.gather(*fs, loop=self)
File "/usr/lib/python3.5/asyncio/futures.py", line 361, in __iter__
yield self # This tells Task to wait for completion.
RuntimeError: Task <Task pending coro=<_wrap_awaitable() running at /usr/lib/python3.5/asyncio/tasks.py:564> cb=[_run_until_complete_cb() at /usr/lib/python3.5/asyncio/base_events.py:164]> got Future <_GatheringFuture pending> attached to a different loop
Code exists with this error.
How to setup loop for websocket to start websocket server in thread?
I have followed this answer but no luck.
You don't have to use threads with asyncio. It's redundant.
Do something like this (I actually don't know what websocket is, I assume start_server is a coroutine \ an awaitable).
Create another async function, deputed to keep the loop alive. Before going into a while loop, spawn your task.
You may want to add an health check, using a global variable or wrapping all into a class.
async def run():
eventLoop.create_task(start_server())
while 1:
# if not health_check():
# exit()
await asyncio.sleep(1)
eventLoop.run_until_complete(run())
Do the other stuff by spawning more tasks.
To run blocking code into an asyncio loop, use eventLoop.run_in_executor(None, blocking_code): it's basically a friendly interface to threads.
As with threads, you live into the GIL.
Embrace the way asyncio do things.

server in a thread (Python3.9.0+aiohttp) : RuntimeError: can't register atexit after shutdown

This snippet of code (a minimal server running in a thread, code taken from here) works fine with Python3.8.3 but raises an error message with Python3.9.0:
import asyncio
import threading
from aiohttp import web
def aiohttp_server():
def say_hello(request):
return web.Response(text='Hello, world')
app = web.Application()
app.add_routes([web.get('/', say_hello)])
runner = web.AppRunner(app)
return runner
def run_server(runner):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(runner.setup())
site = web.TCPSite(runner, 'localhost', 8080)
loop.run_until_complete(site.start())
loop.run_forever()
t = threading.Thread(target=run_server, args=(aiohttp_server(),))
t.start()
The error message:
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python3.9/threading.py", line 954, in _bootstrap_inner
self.run()
File "/usr/lib/python3.9/threading.py", line 892, in run
self._target(*self._args, **self._kwargs)
File "/home/alkhinoos/nikw/nikw/z2.py", line 21, in run_server
loop.run_until_complete(site.start())
File "/usr/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
return future.result()
File "/usr/lib/python3.9/site-packages/aiohttp/web_runner.py", line 121, in start
self._server = await loop.create_server(
File "/usr/lib/python3.9/asyncio/base_events.py", line 1460, in create_server
infos = await tasks.gather(*fs, loop=self)
File "/usr/lib/python3.9/asyncio/base_events.py", line 1400, in _create_server_getaddrinfo
infos = await self._ensure_resolved((host, port), family=family,
File "/usr/lib/python3.9/asyncio/base_events.py", line 1396, in _ensure_resolved
return await loop.getaddrinfo(host, port, family=family, type=type,
File "/usr/lib/python3.9/asyncio/base_events.py", line 856, in getaddrinfo
return await self.run_in_executor(
File "/usr/lib/python3.9/asyncio/base_events.py", line 809, in run_in_executor
executor = concurrent.futures.ThreadPoolExecutor(
File "/usr/lib/python3.9/concurrent/futures/__init__.py", line 49, in __getattr__
from .thread import ThreadPoolExecutor as te
File "/usr/lib/python3.9/concurrent/futures/thread.py", line 37, in <module>
threading._register_atexit(_python_exit)
File "/usr/lib/python3.9/threading.py", line 1374, in _register_atexit
raise RuntimeError("can't register atexit after shutdown")
RuntimeError: can't register atexit after shutdown
What's going on ? The same problem appears with Python 3.9.1. Is this problem solved with Python 3.9.2 ? Maybe a relative issue here.
As mentioned in Python manual - Thread Objects
Other threads can call a thread’s join() method. This blocks the calling thread until the thread whose join() method is called is terminated.
After calling t.start() in main thread, the main thread will exit. Then the process is ended.
If you want to run the child thread forever or until it exits, you should call t.join() in main thread after t.start().
Not sure what you did, but I used 127.0.0.1 instead of localhost and the error is resolved!
I managed to get this sorted by importing the ThreadPoolExecutor module, before calling any of my main application code - so at the top of my main.py start-up script.
thread_pool_ref = concurrent.futures.ThreadPoolExecutor
Just the act of importing the module early (before any threads are initialised) was enough to fix the error. There is an on-going issue around how this module must be present in the main thread, before any child threads import or use any related threading library code.
The inspiration for this fix came from this post on the Python bugs site. My issue was specifically around boto3 library, but the fix is applicable across the board.

No activity or too many missed heartbeats in the last 5 seconds [RabbitMQ]

I followed the example code here: https://github.com/pika/pika/blob/1.1.0/examples/basic_consumer_threaded.py
But after few hours, my consumer stops with the below traceback. No activity or too many missed heartbeats in the last 5 seconds (I set 5 seconds because of following example code)
Traceback (most recent call last):
File "/usr/lib/python3.7/threading.py", line 926, in _bootstrap_inner
self.run()
File "/usr/lib/python3.7/threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "main.py", line 44, in do_word
connection.add_callback_threadsafe(cb)
File "/opt/cdp/at-cdp-product-analysis-consumer/venv/lib/python3.7/site-packages/pika/adapters/blocking_connection.py", line 744, in add_callback_threadsafe
'BlockingConnection.add_callback_threadsafe() called on '
pika.exceptions.ConnectionWrongStateError: BlockingConnection.add_callback_threadsafe() called on closed or closing connection.
Traceback (most recent call last):
File "main.py", line 66, in <module>
rabbit.channel.start_consuming()
File "/opt/cdp/at-cdp-product-analysis-consumer/venv/lib/python3.7/site-packages/pika/adapters/blocking_connection.py", line 1866, in start_consuming
self._process_data_events(time_limit=None)
File "/opt/cdp/at-cdp-product-analysis-consumer/venv/lib/python3.7/site-packages/pika/adapters/blocking_connection.py", line 2027, in _process_data_events
self.connection.process_data_events(time_limit=time_limit)
File "/opt/cdp/at-cdp-product-analysis-consumer/venv/lib/python3.7/site-packages/pika/adapters/blocking_connection.py", line 825, in process_data_events
self._flush_output(common_terminator)
File "/opt/cdp/at-cdp-product-analysis-consumer/venv/lib/python3.7/site-packages/pika/adapters/blocking_connection.py", line 522, in _flush_output
raise self._closed_result.value.error
pika.exceptions.AMQPHeartbeatTimeout: No activity or too many missed heartbeats in the last 5 seconds
Exception in thread Thread-42749:
Traceback (most recent call last):
File "/usr/lib/python3.7/threading.py", line 926, in _bootstrap_inner
self.run()
File "/usr/lib/python3.7/threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "main.py", line 44, in do_word
connection.add_callback_threadsafe(cb)
File "/opt/cdp/at-cdp-product-analysis-consumer/venv/lib/python3.7/site-packages/pika/adapters/blocking_connection.py", line 744, in add_callback_threadsafe
'BlockingConnection.add_callback_threadsafe() called on '
pika.exceptions.ConnectionWrongStateError: BlockingConnection.add_callback_threadsafe() called on closed or closing connection.
Here is my code:
import json
import config
from app import rabbit, elastic
import functools
import threading
# --------------------------------------------
# Ack message
# --------------------------------------------
def ack_message(channel, delivery_tag):
if channel.is_open:
channel.basic_ack(delivery_tag)
else:
pass
# --------------------------------------------
# Parse message to transactions
# --------------------------------------------
def do_word(connection, channel, delivery_tag, body):
# Do something
cb = functools.partial(ack_message, channel, delivery_tag)
connection.add_callback_threadsafe(cb)
# --------------------------------------------
# Callback function for RabbitMQ Consuming
# --------------------------------------------
def callback(channel, method, properties, body, args):
connection, threads = args
t = threading.Thread(target=do_word,
args=(connection, channel, method.delivery_tag, body))
t.start()
threads.append(t)
if __name__ == "__main__":
# Consuming config
threads = []
# I declare exchange, channel in another python file and call as rabbit object.
message_callback = functools.partial(callback, args=(rabbit.connection, threads))
rabbit.channel.basic_consume(queue=config.RABBITMQ_TRANSACTION_QUEUE, on_message_callback=message_callback)
# Start Consuming
rabbit.channel.start_consuming()
# Wait for all to complete
for thread in threads:
thread.join()
rabbit.connection.close()
What if my heartbeat configuration was too low (5 seconds). Should I disable heartbeat?
pika: 1.1.0

Optional user input with timeout for Python 3

I am trying to make a code that will ask for a user input and if that input is not given in a set amount of time will assume a default value and continue through the rest of the code without requiring the user to hit enter. I am running in Python 3.5.1 on Windows 10.
I have looked through: Keyboard input with timeout in Python, How to set time limit on raw_input, Timeout on a function call, and Python 3 Timed Input black boxing the answers but none of the answers are suitable as they are not usable on Windows (principally use of signal.SIGALRM which is only available on linux), or require a user to hit enter in order to exit the input.
Based upon the above answers however i have attempted to scrap together a solution using multiprocessing which (as i think it should work) creates one process to ask for the input and creates another process to terminate the first process after the timeout period.
import multiprocessing
from time import time,sleep
def wait(secs):
if secs == 0:
return
end = time()+secs
current = time()
while end>current:
current = time()
sleep(.1)
return
def delay_terminate_process(process,delay):
wait(delay)
process.terminate()
process.join()
def ask_input(prompt,term_queue,out_queue):
command = input(prompt)
process = term_queue.get()
process.terminate()
process.join()
out_queue.put(command)
##### this doesn't even remotly work.....
def input_with_timeout(prompt,timeout=15.0):
print(prompt)
astring = 'no input'
out_queue = multiprocessing.Queue()
term_queue = multiprocessing.Queue()
worker1 = multiprocessing.Process(target=ask_input,args=(prompt,term_queue,out_queue))
worker2 = multiprocessing.Process(target=delay_terminate_process,args=(worker1,timeout))
worker1.daemon = True
worker2.daemon = True
term_queue.put(worker2)
print('Through overhead')
if __name__ == '__main__':
print('I am in if statement')
worker2.start()
worker1.start()
astring = out_queue.get()
else:
print('I have no clue what happened that would cause this to print....')
return
print('returning')
return astring
please = input_with_timeout('Does this work?',timeout=10)
But this fails miserably and yields:
Does this work?
Through overhead
I am in if statement
Traceback (most recent call last):
File "C:\Anaconda3\lib\multiprocessing\queues.py", line 241, in _feed
obj = ForkingPickler.dumps(obj)
File "C:\Anaconda3\lib\multiprocessing\reduction.py", line 50, in dumps
cls(buf, protocol).dump(obj)
File "C:\Anaconda3\lib\multiprocessing\queues.py", line 58, in __getstate__
context.assert_spawning(self)
File "C:\Anaconda3\lib\multiprocessing\context.py", line 347, in assert_spawning
' through inheritance' % type(obj).__name__
RuntimeError: Queue objects should only be shared between processes through inheritance
Does this work?
Through overhead
I have no clue what happened that would cause this to print....
Does this work?Process Process-1:
Traceback (most recent call last):
File "C:\Anaconda3\lib\multiprocessing\queues.py", line 241, in _feed
obj = ForkingPickler.dumps(obj)
File "C:\Anaconda3\lib\multiprocessing\reduction.py", line 50, in dumps
cls(buf, protocol).dump(obj)
File "C:\Anaconda3\lib\multiprocessing\process.py", line 287, in __reduce__
'Pickling an AuthenticationString object is '
TypeError: Pickling an AuthenticationString object is disallowed for security reasons
Traceback (most recent call last):
File "C:\Anaconda3\lib\multiprocessing\process.py", line 254, in _bootstrap
self.run()
File "C:\Anaconda3\lib\multiprocessing\process.py", line 93, in run
self._target(*self._args, **self._kwargs)
File "C:\Anaconda3\saved_programs\a_open_file4.py", line 20, in ask_input
command = input(prompt)
EOFError: EOF when reading a line
Does this work?
Through overhead
I have no clue what happened that would cause this to print....
Traceback (most recent call last):
File "C:\Anaconda3\lib\multiprocessing\queues.py", line 241, in _feed
obj = ForkingPickler.dumps(obj)
File "C:\Anaconda3\lib\multiprocessing\reduction.py", line 50, in dumps
cls(buf, protocol).dump(obj)
File "C:\Anaconda3\lib\multiprocessing\queues.py", line 58, in __getstate__
context.assert_spawning(self)
File "C:\Anaconda3\lib\multiprocessing\context.py", line 347, in assert_spawning
' through inheritance' % type(obj).__name__
RuntimeError: Queue objects should only be shared between processes through inheritance
Process Process-2:
Traceback (most recent call last):
File "C:\Anaconda3\lib\multiprocessing\process.py", line 254, in _bootstrap
self.run()
File "C:\Anaconda3\lib\multiprocessing\process.py", line 93, in run
self._target(*self._args, **self._kwargs)
File "C:\Anaconda3\saved_programs\a_open_file4.py", line 16, in delay_terminate_process
process.terminate()
File "C:\Anaconda3\lib\multiprocessing\process.py", line 113, in terminate
self._popen.terminate()
AttributeError: 'NoneType' object has no attribute 'terminate'
I really don't understand the multiprocessing module well and although I have read the official docs am unsure why this error occurred or why it appears to have ran through the function call 3 times in the process. Any help on how to either resolve the error or achieve an optional user input in a cleaner manner will be much appreciated by a noob programmer. Thanks!

Resources