I have to launch discord.py in a separate thread since I can't block my main thread.
It is a game server C/Python 3.7 (ubuntu 18)
C code:
int pysDiscord_Init;
...
PyObject *psv_discord;
psv_discord = Python_LoadModule("sv_discord");
if (psv_discord != NULL) {
pysDiscord_Init = Python_RegisterFunction(psv_discord, "sv_discord", "init");
Python_Execute(pysDiscord_Init, "");
}
sv_discord.py
import discord
import asyncio
import threading
from concurrent.futures import ThreadPoolExecutor
import multiprocessing
TOKEN = '12345'
client = discord.Client()
def init():
print("Initializing Discord...")
print("current_thread: %s" % threading.current_thread())
t = threading.Thread(target=client.run, args=(TOKEN,))
t.start()
or
def init():
print("Initializing Discord...")
print("current_thread: %s" % threading.current_thread())
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
asyncio.get_child_watcher().attach_loop(loop)
pool = ThreadPoolExecutor(max_workers=multiprocessing.cpu_count())
task = loop.run_in_executor(pool, client.run, TOKEN)
loop.run_until_complete(task)
set_wakeup_fd exception:
...
Initializing Discord...
current_thread: <_MainThread(MainThread, started 4150019840)>
Exception in thread Thread-1:
Traceback (most recent call last):
File "./build/Lib/asyncio/unix_events.py", line 92, in add_signal_handler
ValueError: set_wakeup_fd only works in main thread
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "./build/Lib/threading.py", line 917, in _bootstrap_inner
File "./build/Lib/threading.py", line 865, in run
File "./../source/discord.py-rewrite/discord/client.py", line 550, in run
File "./build/Lib/asyncio/unix_events.py", line 94, in add_signal_handler
RuntimeError: set_wakeup_fd only works in main thread
I should mention that I tried the same code on the python (without the C code) and it works.
This error tells me about the main thread. But I don't create sv_discord
inside the new thread, and as you can see from the log, it is the "Main"
thread inside init()
method. I don't understand this.
Answering my own question:
I should thank this source asyncio-you-are-a-complex-beast where I finally found a solution.
The final working code looks like this:
import discord
import asyncio
from threading import Thread
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
print("on_message content: %s, channel: %s" % (message.content, message.channel))
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))
My main mistake was that for the game I compiled and used the latest rewrite
version while inside the system over the pip I got 0.16.12
and read the documentation for 0.16.12 while I had to look at discord.py.rewrite (for example inside on_message
I used wrong client.send_message
while I had to use message.channel.send
)
I had a similar edge case (not really the intended use of asyncio
but what the hell) where I needed to Thread the discord.py
instance.
I ended up modifying your solution with the following:
class discordHost(discord.Client):
async def on_ready(self):
print(f'{DThread.discord_client.user} has connected.')
class Threader(Thread):
def __init__(self):
Thread.__init__(self)
self.loop = asyncio.get_event_loop()
self.start()
async def starter(self):
self.discord_client = discordHost()
await self.discord_client.start(DISCORD_TOKEN)
def run(self):
self.name = 'Discord.py'
self.loop.create_task(self.starter())
self.loop.run_forever()
if not 'Discord.py' in [t.name for t in tenumerate()]:
DThread = Threader()
This does more or less the same thing, but I've subclassed Thread
and subclassed discord.Client
to more easily work with the outcome of the two.
The only caveat here, is that asyncio.get_event_loop()
has to be called before Thread.start()
, otherwise it gets confused and losses it's context of the main thread.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With