I am trying to build a websockets server where the client connects and sends a request of some kind, and then the server adds that request to a queue and returns something back when finished.
to simulate the process of queueing and waiting for tasks to finish, I called asyncio.sleep whenever the process is supposed to be called.
however, whenever I do that I get the following error from the client-side:
Traceback (most recent call last):
File "D:/Python/server/client1.py", line 10, in <module>
asyncio.get_event_loop().run_until_complete(message())
File "C:\ProgramData\Anaconda3\envs\server\lib\asyncio\base_events.py", line 587, in run_until_complete
return future.result()
File "D:/Python/server/client1.py", line 8, in message
print(await socket.recv())
File "C:\ProgramData\Anaconda3\envs\server\lib\site-packages\websockets\protocol.py", line 509, in recv
await self.ensure_open()
File "C:\ProgramData\Anaconda3\envs\server\lib\site-packages\websockets\protocol.py", line 812, in ensure_open
raise self.connection_closed_exc()
websockets.exceptions.ConnectionClosedOK: code = 1000 (OK), no reason
and this error from the server-side:
Task exception was never retrieved
future: <Task finished coro=<queue_dispatcher() done, defined at D:/RamNew2020/Python/server/asyncserver.py:39> exception=ConnectionClosedOK('code = 1000 (OK), no reason')>
Traceback (most recent call last):
File "D:/Python/server/asyncserver.py", line 45, in queue_dispatcher
await data_from_q.sendto_websocket("yay")
File "D:/Python/server/asyncserver.py", line 20, in sendto_websocket
await self.mywebsocket.send(message)
File "C:\ProgramData\Anaconda3\envs\server\lib\site-packages\websockets\protocol.py", line 555, in send
await self.ensure_open()
File "C:\ProgramData\Anaconda3\envs\server\lib\site-packages\websockets\protocol.py", line 803, in ensure_open
raise self.connection_closed_exc()
websockets.exceptions.ConnectionClosedOK: code = 1000 (OK), no reason
My scripts:
server.py:
import asyncio
import websockets
import datetime
import random
queue = asyncio.Queue()
async def rnd_sleep(t):
# sleep for T seconds on average
await asyncio.sleep(t * random.random() * 2)
#When a client sends a message the information is saved in a Request object,
#including the socket connection
class Request:
def __init__(self, mywebsocket, mydat):
self.mywebsocket = mywebsocket
self.mydat = mydat
self.start_time_of_request = datetime.datetime.now()
self.id = random.randint(0, 128)
async def sendto_websocket(self, message):
await self.mywebsocket.send(message)
def get_dat(self):
return self.mydat
def get_start_time(self):
return self.start_time_of_request
async def add_to_queue(websocket, path):
global queue
dat = await websocket.recv()
base64dat = Request(websocket, dat)
await queue.put(base64dat)
#problem in queue_dispatcher
async def queue_dispatcher(q):
while True:
data_from_q = await q.get()
print(data_from_q.id)
await asyncio.sleep(1) #The problem is here, whenever I remove it, it works
await data_from_q.sendto_websocket("yay")
q.task_done()
async def main():
global queue
asyncio.create_task(queue_dispatcher(queue))
pass
start_server = websockets.serve(add_to_queue, 'localhost', 5000)
asyncio.get_event_loop().run_until_complete(main())
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
client.py:
import asyncio
async def message():
async with websockets.connect("ws://localhost:5000")as socket:
msg = input("What do you want to send: ")
await socket.send(msg)
print(await socket.recv())
asyncio.get_event_loop().run_until_complete(message())
In addition, whenever I try to await any other async function, it works fine no matter how long.
Related
Goals
Running multiple bot in the same time with same command
What I've tried
I've coded and searching through internet I found this. I know it's the answer but if I created client1 and client2. Here in my code I just make 1 client (client1)
token1 = getenv("TOKEN1")
token2 = getenv("TOKEN2")
intents = discord.Intents().all()
client1 = commands.Bot(command_prefix = '.', intents = intents)
slash = SlashCommand(client1, sync_commands=True)
client1.remove_command('help')
#client1.event
async def on_ready():
await client1.change_presence(activity=discord.Game(name='Bot Ready'))
print("logged in")
for filename in listdir('cogs'):
if filename.endswith('.py'):
client1.load_extension(f'cogs.{filename[:-3]}')
def meFunction(ctx):
return ctx.author.id == 385053392059236353
loop = asyncio.get_event_loop()
loop.create_task(client1.start(token1))
loop.create_task(client1.start(token2))
loop.run_forever()
And then this warning message appear in my command prompt
client_session: <aiohttp.client.ClientSession object at 0x00000247DB381BE0>
Unclosed connector
connections: ['[(<aiohttp.client_proto.ResponseHandler object at 0x00000247DB370D60>, 2262.609)]']
connector: <aiohttp.connector.TCPConnector object at 0x00000247DB38E280>
Task exception was never retrieved
future: <Task finished name='Task-5' coro=<Client.start() done, defined at C:\Users\chris\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\client.py:649> exception=RuntimeError('Concurrent call to receive() is not allowed')>
Traceback (most recent call last):
File "C:\Users\chris\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\client.py", line 666, in start
await self.connect(reconnect=reconnect)
File "C:\Users\chris\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\client.py", line 566, in connect
await self.ws.poll_event()
File "C:\Users\chris\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\gateway.py", line 555, in poll_event
msg = await self.socket.receive(timeout=self._max_heartbeat_timeout)
File "C:\Users\chris\AppData\Local\Programs\Python\Python39\lib\site-packages\aiohttp\client_ws.py", line 216, in receive
raise RuntimeError("Concurrent call to receive() is not allowed")
RuntimeError: Concurrent call to receive() is not allowed
Last solution what I know is making client2 which is copy of client1
I am trying to run multiple discord bots with the same script at once. The way I am doing this is going down a csv file, to get the bot token and bot name. I then start my script:
import time, csv, re, random, string, sys, os, asyncio
from datetime import datetime
from threading import Thread
import discord
from dotenv import load_dotenv
from discord_webhook import DiscordWebhook, DiscordEmbed
def main(bottoken, botname):
TOKEN = (bottoken)
client = discord.Client()
#client.event
async def on_ready():
print(f'{client.user.name} has connected to Discord!')
#client.event
async def on_message(message):
#do stuff
print('Do stuff')
client.run(TOKEN)
def runtask():
if __name__ == '__main__':
with open('botinfo.csv', 'r') as f:
reader = csv.reader(f, delimiter=',')
for i, row in enumerate(reader):
Thread(target = main, args=(row[0], row[1])).start()
if __name__ == '__main__':
runtask()
But then I get this error:
Exception in thread Thread-1:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py", line 917, in _bootstrap_inner
self.run()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "/Users/alexforman/Documents/GitHub/bot-price-monitor/frontend_multithread.py", line 14, in main
client = discord.Client()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/discord/client.py", line 216, in __init__
self.loop = asyncio.get_event_loop() if loop is None else loop
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/events.py", line 644, in get_event_loop
% threading.current_thread().name)
RuntimeError: There is no current event loop in thread 'Thread-1'.
Exception in thread Thread-2:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py", line 917, in _bootstrap_inner
self.run()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "/Users/alexforman/Documents/GitHub/bot-price-monitor/frontend_multithread.py", line 14, in main
client = discord.Client()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/discord/client.py", line 216, in __init__
self.loop = asyncio.get_event_loop() if loop is None else loop
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/events.py", line 644, in get_event_loop
% threading.current_thread().name)
RuntimeError: There is no current event loop in thread 'Thread-2'.
Does anyone have any ideas on how I could fix it?
You don't need to start a separate thread for each bot, the asyncio event loop is perfectly capable of serving all bots at once. (That's the kind of thing event loops are designed for.)
You just need to start all the bots as coroutines of the same asyncio event loop:
async def run_client(bottoken, botname):
TOKEN = (bottoken)
client = discord.Client()
#client.event
async def on_ready():
print(f'{client.user.name} has connected to Discord!')
#client.event
async def on_message(message):
#do stuff
print('Do stuff')
# can't use client.run() because it would block the event loop
# but we can use client.start(), which is a coroutine that does
# the same thing (and which is internally called by client.run)
await client.start(TOKEN)
async def main():
coros = []
with open('botinfo.csv', 'r') as f:
reader = csv.reader(f, delimiter=',')
for i, row in enumerate(reader):
coros.append(run_client(row[0], row[1]))
await asyncio.gather(*coros)
if __name__ == '__main__':
asyncio.run(main())
i've been trying to create a discord bot that can receive commands through a web interface. I'm using discord.py as a Discord API wrapper and Quart as a REST framework, because i need to handle asynchronous tasks and Flask doesn't support them.
Right now i have two files:
app.py
import discord
bot = discord.Client(intents=discord.Intents.all())
...
async def play_audio(audio_name, voiceChannel):
vc = await voiceChannel.connect()
print("test")
vc.play(discord.FFmpegPCMAudio(source="audio\{}".format(audio_name), executable=FFMPEG_PATH))
while vc.is_playing():
time.sleep(.1)
await vc.disconnect()
async def get_online_voice_members():
guild = bot.get_guild(NMC_GUILD_ID)
online_voice_users = {}
for voiceChannel in guild.voice_channels:
for user in voiceChannel.members:
online_voice_users[user] = voiceChannel
return online_voice_users
...
api.py
import asyncio
from quart import Quart
import app as discord
QUART_APP = Quart(__name__)
#QUART_APP.before_serving
async def before_serving():
loop = asyncio.get_event_loop()
await discord.bot.login("MY BOT TOKEN")
loop.create_task(discord.bot.connect())
...
#QUART_APP.route("/online_list", methods=["GET"])
async def get_online_members():
resp = {}
members = await discord.get_online_voice_members()
for user in members.keys():
resp[user.id] = {"nick" : user.nick, "channel" : members[user].id}
return resp
#QUART_APP.route("/goodnight", methods=["GET"])
async def send_goodnight():
members = await discord.get_online_voice_members()
for user in members.keys():
if user.id == 12345:
await discord.play_audio("goodnight.mp3", members[user])
break
return {"response":"OK"}
When i make a GET request on the endpoint /online_list everything works fine, but when i make a request on /goodnight, the code successfully runs until reaching the instruction await discord.play_audio("goodnight.mp3, members[user]), which receives the correct parameters, but it always raises the following exception:
Traceback (most recent call last):
File "G:\Gunther\venv\lib\site-packages\quart\app.py", line 1814, in handle_request
return await self.full_dispatch_request(request_context)
File "G:\Gunther\venv\lib\site-packages\quart\app.py", line 1836, in full_dispatch_request
result = await self.handle_user_exception(error)
File "G:\Gunther\venv\lib\site-packages\quart\app.py", line 1076, in handle_user_exception
raise error
File "G:\Gunther\venv\lib\site-packages\quart\app.py", line 1834, in full_dispatch_request
result = await self.dispatch_request(request_context)
File "G:\Gunther\venv\lib\site-packages\quart\app.py", line 1882, in dispatch_request
return await handler(**request_.view_args)
File "G:/Dati HDD F/GitHub Projects/Gunther/api.py", line 59, in send_buonanotte
await discord.play_audio("goodnight.mp3", members[user])
File "G:\Gunther\app.py", line 55, in play_audio
vc = await voiceChannel.connect()
File "G:\Gunther\venv\lib\site-packages\discord\abc.py", line 1122, in connect
await voice.connect(timeout=timeout, reconnect=reconnect)
File "G:\Gunther\venv\lib\site-packages\discord\voice_client.py", line 352, in connect
self.ws = await self.connect_websocket()
File "G:\Gunther\venv\lib\site-packages\discord\voice_client.py", line 323, in connect_websocket
await ws.poll_event()
File "G:\Gunther\venv\lib\site-packages\discord\gateway.py", line 893, in poll_event
await self.received_message(json.loads(msg.data))
File "G:\Gunther\venv\lib\site-packages\discord\gateway.py", line 825, in received_message
await self.initial_connection(data)
File "G:\Gunther\venv\lib\site-packages\discord\gateway.py", line 849, in initial_connection
recv = await self.loop.sock_recv(state.socket, 70)
File "C:\Users\Kyles\AppData\Local\Programs\Python\Python38\lib\asyncio\proactor_events.py", line 693, in sock_recv
return await self._proactor.recv(sock, n)
RuntimeError: Task <Task pending name='Task-27' coro=<ASGIHTTPConnection.handle_request() running at G:\Gunther\venv\lib\site-packages\quart\asgi.py:70> cb=[_wait.<locals>._on_completion() at C:\Users\Kyles\AppData\Local\Programs\Python\Python38\lib\asyncio\tasks.py:507]> got Future <_OverlappedFuture pending overlapped=<pending, 0x199c31f0ca0>> attached to a different loop
I guess i'm not understanding correctly how the asyncio library works, as it seems to me that no matter what i try, the line vc = await voiceChannel.connect() in app.py always ends up running on a different loop than the main one. Is there something i'm missing?
This is because you initiate the discord client on import (line 3 of app.py). Doing so means that it will use the event loop available at the time of import. However, Quart (and Hypercorn unless told not too) will close the existing loop and create a new one as it starts. It is for this reason that I recommend utilizing the startup functionality for initialization.
To solve this I would wrap your discord commands in a class and initialize it in a startup function. Note that I like storing instances on the app itself (so they can be accessed via the current_app proxy), this is not necessary though. For example,
app.py
class DiscordClient:
def __init__(self):
self.bot = discord.Client(intents=discord.Intents.all())
...
async def get_online_voice_members(self):
guild = self.bot.get_guild(NMC_GUILD_ID)
...
api.py
#QUART_APP.before_serving
async def before_serving():
loop = asyncio.get_event_loop()
QUART_APP.discord_client = DiscordClient()
await QUART_APP.discord_client.bot.login("MY BOT TOKEN")
loop.create_task(QUART_APP.discord_client.bot.connect())
#QUART_APP.route("/online_list", methods=["GET"])
async def get_online_members():
resp = {}
members = await QUART_APP.discord_client.get_online_voice_members()
...
I was trying to use Telethon but turns out is really slow
So I tried using this gist as suggested in
this post
I have the following errors . Can anyone please help me?
Here is my code:
from telethon.sync import TelegramClient
from FastTelethon import download_file
import os
import asyncio
async def getAllMediaFromchannel():
os.chdir("/home/gtxtreme/Documents/McHumour")
api_hash = "<hidden>"
api_id = <hidden>
client = TelegramClient('MCHumour', api_id, api_hash)
client.start()
ch_entity = await client.get_entity("telegram.me/joinchat/AAAAAEXnb4jK7xyU1SfAsw")
messages = client.iter_messages(ch_entity, limit=50)
def progress_cb(current, total):
print('Uploaded', current, 'out of', total,
'bytes: {:.5%}'.format(current / total))
async for msg in messages:
result = await download_file(client, msg.document, "/home/gtxtreme/Documents/McHumour",
progress_callback=progress_cb)
print("*************************\nFile named {0} saved to {1} successfully\n********************".format(
msg.message, result))
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(getAllMediaFromchannel())
Here is my error
[gtxtreme#archlinux ~]$ python PycharmProjects/python_gtxtreme/tgBotrev1.py
PycharmProjects/python_gtxtreme/tgBotrev1.py:13: RuntimeWarning: coroutine 'AuthMethods._start' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
Traceback (most recent call last):
File "PycharmProjects/python_gtxtreme/tgBotrev1.py", line 31, in <module>
loop.run_until_complete(getAllMediaFromchannel())
File "/usr/lib/python3.8/asyncio/base_events.py", line 612, in run_until_complete
return future.result()
File "PycharmProjects/python_gtxtreme/tgBotrev1.py", line 14, in getAllMediaFromchannel
ch_entity = await client.get_entity("telegram.me/joinchat/AAAAAEXnb4jK7xyU1SfAsw")
File "/usr/lib/python3.8/site-packages/telethon/client/users.py", line 310, in get_entity
result.append(await self._get_entity_from_string(x))
File "/usr/lib/python3.8/site-packages/telethon/client/users.py", line 512, in _get_entity_from_string
invite = await self(
File "/usr/lib/python3.8/site-packages/telethon/client/users.py", line 30, in __call__
return await self._call(self._sender, request, ordered=ordered)
File "/usr/lib/python3.8/site-packages/telethon/client/users.py", line 56, in _call
future = sender.send(request, ordered=ordered)
File "/usr/lib/python3.8/site-packages/telethon/network/mtprotosender.py", line 170, in send
raise ConnectionError('Cannot send requests while disconnected')
ConnectionError: Cannot send requests while disconnected
[gtxtreme#archlinux ~]$
Also any other suitable way of doing it would be preferred
client.start is an async method so you should await it.
it only needs the await if it is inside a function. if you call it outside of a function telethon adds the await implicitly for convenience
I want to try Multi Agent programming in Python using SPADE, but i can't seem to make this simple example work. The error refers to the server, so how can i set up the agents to work in the localhost ?
here is my code :
class SenderAgent(Agent):
class InformBehav(OneShotBehaviour):
async def run(self):
print("InformBehav running")
msg = Message(to="receiveragent#127.0.0.1") # Instantiate the message
msg.set_metadata("performative", "inform") # Set the "inform" FIPA performative
msg.body = "Hello World" # Set the message content
await self.send(msg)
print("Message sent!")
# stop agent from behaviour
await self.agent.stop()
async def setup(self):
print("SenderAgent started")
b = self.InformBehav()
self.add_behaviour(b)
class ReceiverAgent(Agent):
class RecvBehav(OneShotBehaviour):
async def run(self):
print("RecvBehav running")
msg = await self.receive(timeout=10) # wait for a message for 10 seconds
if msg:
print("Message received with content: {}".format(msg.body))
else:
print("Did not received any message after 10 seconds")
# stop agent from behaviour
await self.agent.stop()
async def setup(self):
print("ReceiverAgent started")
b = self.RecvBehav()
template = Template()
template.set_metadata("performative", "inform")
self.add_behaviour(b, template)
if __name__ == "__main__":
receiveragent = ReceiverAgent("receiveragent#127.0.0.1", '1234')
future = receiveragent.start()
future.result() # wait for receiver agent to be prepared.
senderagent = SenderAgent("senderagent#127.0.0.1", '1234')
senderagent.start()
while receiveragent.is_alive():
try:
time.sleep(1)
except KeyboardInterrupt:
senderagent.stop()
receiveragent.stop()
break
print("Agents finished")
as i'm getting the following errors :
connection failed: [Errno 10061] Connect call failed ('127.0.0.1', 5222)
Traceback (most recent call last):
File "C:/Users/Administrateur/PycharmProjects/spade/test.py", line 53, in <module>
future.result() # wait for receiver agent to be prepared.
File "C:\Users\Administrateur\AppData\Local\Programs\Python\Python37\lib\concurrent\futures\_base.py", line 435, in result
return self.__get_result()
File "C:\Users\Administrateur\AppData\Local\Programs\Python\Python37\lib\concurrent\futures\_base.py", line 384, in __get_result
raise self._exception
File "C:\Users\Administrateur\AppData\Local\Programs\Python\Python37\lib\site-packages\spade\agent.py", line 100, in _async_start
await self._async_register()
File "C:\Users\Administrateur\AppData\Local\Programs\Python\Python37\lib\site-packages\spade\agent.py", line 142, in _async_register
_, stream, features = await aioxmpp.node.connect_xmlstream(self.jid, metadata, loop=self.loop)
File "C:\Users\Administrateur\AppData\Local\Programs\Python\Python37\lib\site-packages\aioxmpp\node.py", line 415, in connect_xmlstream
exceptions
aioxmpp.errors.MultiOSError: failed to connect to XMPP domain '127.0.0.1': multiple errors: [Errno 10061] Connect call failed ('127.0.0.1', 5222)