Rapptz / discord.py

An API wrapper for Discord written in Python.
http://discordpy.rtfd.org/en/latest
MIT License
14.8k stars 3.75k forks source link

Can't send message from another function #481

Closed drequivalent closed 7 years ago

drequivalent commented 7 years ago

Hello. I'm wtiting Discord - XMPP transport based on SleekXMPP and your lib.

I've run into trouble trying to take a message from XMPP conference and send it into Discord channel.

disclient = discord.Client()
channelnumber = '280108335502589953'

class MainXBot(sleekxmpp.ClientXMPP):
    def __init__(self, jid, password, room, nick):
        sleekxmpp.ClientXMPP.__init__(self, jid, password)

        self.room = room
        self.nick = nick

        self.add_event_handler("session_start", self.start)
        self.add_event_handler("groupchat_message", self.muc_message)

    def start(self, event):
        print("Session started")
        self.get_roster()
        self.send_presence()
        self.plugin['xep_0045'].joinMUC(self.room, self.nick, wait=True)
        print("Conference " + self.room + " joined")
        #~ self.send_message(mto=self.room, mbody="Wazup Peaches.", mtype='groupchat')
        #help(self)
        return

    def muc_message(self, msg):
        print(msg['body'])
        if msg['mucnick'] != self.nick:
            message = disclient.send_message(disclient.get_channel(channelnumber), msg['body'])
            print(message)

The last two lines return the generator object, but no message appears in the Discord channel.

Is there a way to send a message while outside of discord.py's event handling?

NotSoSuper commented 7 years ago

Of course it's not going to work. First, you don't even run the bot, second none of your functions are async, the client.send_message is returning a coroutine which is never awaited.

If you just need to send messages, you might as well just manually make the message request to the endpoint with the requests module, read https://discordapp.com/developers/docs/intro

Rapptz commented 7 years ago

If all you're doing is sending messages via a relay of sorts, I recommend using a webhook. You can find docs on it here. And some example code here.

drequivalent commented 7 years ago

@NotSoSuper I do run the bot, I just didn't show it. As well as creating MainXBot, as well as a lot of different things. It's strongly implied though, as I'm able to get to generator returned by send_message. Sleekxmpp doesn't work with asyncio, to my knowledge.

@Rapptz I'm sending both ways. That means from Discord to XMPP and from XMPP to Discord.

Rapptz commented 7 years ago

The 'nicest' way would probably be to use a library that supports asyncio right out of the gate, e.g. https://github.com/horazont/aioxmpp

Outside of that, it depends on your threading model.

If this XMPP client is in the same thread as the discord bot you can take the easy way and just post it to the event loop for it to do it at another point e.g. client.loop.create_task(client.send_message(...)).

If it's in a separate thread you'll have to juggle a bit more by running something like this (docs):

f = asyncio.run_coroutine_threadsafe(client.send_message(...), client.loop)
try:
  f.result()
except Exception as e:
  # error happened
drequivalent commented 7 years ago

to use a library that supports asyncio right out of the gate

Yes, I thought about that today morning. Figured, I don't have time or energy to learn another library though. Guess, I chose wrong.

client.loop.create_task

Worked like a fscking miracle.

That's my first real journey into async, so there's things I don't fully understand, I guess, so I appologize if it was a stupid question. Love.

Rapptz commented 7 years ago

Good to know. Good luck with your relay.

DigYang commented 1 year ago

The 'nicest' way would probably be to use a library that supports asyncio right out of the gate, e.g. https://github.com/horazont/aioxmpp

Outside of that, it depends on your threading model.

If this XMPP client is in the same thread as the discord bot you can take the easy way and just post it to the event loop for it to do it at another point e.g. client.loop.create_task(client.send_message(...)).

If it's in a separate thread you'll have to juggle a bit more by running something like this (docs):

f = asyncio.run_coroutine_threadsafe(client.send_message(...), client.loop)
try:
  f.result()
except Exception as e:
  # error happened

Thanks a lot,Good luck with your relay.