jaraco / irc

Full-featured Python IRC library for Python.
MIT License
390 stars 84 forks source link

Is there a way to start a SimpleIRCClient without being blocked in Reactor.porcess_forever() ? #147

Closed MoaMoaK closed 5 years ago

MoaMoaK commented 6 years ago

I want to write a client which can send messages to a channel when an external function triggers it. Basically doing something like:

a = IRCClient('myIRCserver.net', 'myNickName', '#myIRCChannel')
a.send("foo ?")
a.send("bar !")

So I wrote a very basic IRCClient class inspired by scripts/irccat2.py:

class IRCClient(irc.client.SimpleIRCClient):
    def __init__(self, server, nickname, channel, port=6667):
        self.channel = channel
        super(IRCClient, self).__init__()
        # Connect to server
        self.connect(server, port, nickname)
        self.start()

    def on_welcome(self, connection, event):
        connection.join(self.channel)

    def send(self, message):
        self.connection.privmsg(self.channel, message)

The problem is the process is getting stuck in the loop of the self.start() call and never reaches the a.send(...) calls. And not calling self.start() prevents the messages to be transmitted to the server. So is there a way to not completely block the process but still be able to send messages later in the process ?

jaraco commented 6 years ago

Hi, and thanks for checking out the IRC lib!

Because of the nature of IRC, the client needs to be connected and responding to events (such as pings from the server). Therefore, something needs to regularly (continuously) call process_once, and that's what process_forever does.

There are several ways you can work within this constraint.

Probably the easiest way would be to configure your client to run in a thread... and you may be able to still send messages from that client in your main thread.

Another way would be to create an event loop for your application that periodically calls process_once, and have that event loop handle concurrency across the two domains (IRC client and your app's behavior).

Yet another way would be to hook into the IRC Client's event loop, having it call your application's behavior.

For an example, this plugin for pmxbot starts up a web server. At startup, it creates a web server that posts messages to a queue, and the event loop periodically relays messages from that queue to the IRC connection.

There are probably other opportunities if you use the asyncio client, but I'll admit I haven't used it yet, so wouldn't even be able to provide a good example.

I hope that helps.