I'm running an IRC bot, I finally figured out how to whois to properly get auth of an user. I'm now looking to implement this check to referrence against my database instead of relying on their username.
I have a command
def privmsg(self, user, channel, msg):
if msg.startswith(".join"):
# sends whois signal
irc.IRCClient.whois(self, user, None)
I need to get variable from a function that gets called by outcoming source (IRC server), therefore I can't just AddCallback
auth = ???
player = db.getplayer(auth)
I'm receiving auth through
def irc_330(self, prefix, params):
auth = params[2]
I can't seem to figure out how exactly to send the variable back to the first function, or even how to wait for that signal to come back. My first function will pass anything irc_330() does before it even starts.
The only solution I can think of is create a callback function that will wait for a call of function inside that to then return what I need. But that doesn't seem right at all.
The problem that you're running into here is that IRCClient
's API is rather
crummy (sorry about that!). Specifically, it has APIs like .whois()
which
should return a Deferred
, but don't.
You can fix this problem by making your own version of these APIs which do,
in fact, return a Deferred
.
The general idea is that IRC requests and responses don't have request-IDs, so
they are always answered in order. That means you need to establish a queue of
first-in/first-out requests so you can match them to replies as the replies
arrive. Also, you need to match the Deferred firing to the end of the query
(in your case, WHOIS, and therefore, RPL_ENDOFWHOIS
), since IRC servers may
or may not send a particular field as part of the response.
Here's an example implementation of just that:
from collections import deque
from twisted.internet.defer import Deferred
from twisted.words.protocols.irc import IRCClient
class NoAccount(Exception):
"No account found."
class MyClient(IRCClient, object):
def __init__(self):
self._whoisQueue = deque()
def deferredWhois(self, nick):
result = Deferred()
self._whoisQueue.append((result, nick))
self.whois(nick)
return result
def irc_330(self, prefix, params):
self._currentActiveNick = params[2]
def irc_RPL_ENDOFWHOIS(self, prefix, params):
deferredToFire, who = self._whoisQueue.popleft()
currentActiveNick = self._currentActiveNick
self._currentActiveNick = None
if currentActiveNick is None:
deferredToFire.errback(NoAccount(who))
else:
deferredToFire.callback(currentActiveNick)
This makes the deferredWhois
method return a Deferred
that fires with the
account name of the given nick.
Hope this helps!