首页 文章

Twisted Python - IRC客户端

提问于
浏览
2

第一个问题在这里

因此,对于学校的俱乐部,我们正致力于使用Python和Twisted制作IRC客户端 .

所以我采取扭曲给你的机器人的例子 . 我已经设法将它连接到irc Channels ,然后记录 .

我知道我可能必须使用2个线程同时从服务器读取并同时输入,这是我可以实现的,但仅限于命令行输入 . 请注意,它仍在同时记录来自 Channels 的数据 .

所以为了做到这一点,我使用了: d = threads.deferToThread(aSillyBlockingMethod)

哪个叫我 raw_input() 循环 .

我的问题在于无法弄清楚如何通过从命令行输入和打印来改变这一点;能够实际向irc服务器发送消息供其他人阅读 .

任何帮助将不胜感激 . 我是一个新手python程序员,不知道太多web内容;像协议,端口和类似的东西,但我正在慢慢接受它们 . 如果有人知道更简单的方法,请告诉我,我不会致力于使用Twisted .

这是我的代码,或者更确切地说是我正在修改的修改后的机器人:

# twisted imports
from twisted.words.protocols import irc
from twisted.internet import reactor, protocol
from twisted.python import log
from twisted.internet import threads

# system imports
import time, sys

class MessageLogger:
    """
    An independent logger class (because separation of application
    and protocol logic is a good thing).
    """
    def __init__(self, file):
        self.file = file

    def log(self, message):
        """Write a message to the file."""
        timestamp = time.strftime("[%H:%M:%S]", time.localtime(time.time()))
        self.file.write('%s %s\n' % (timestamp, message))
        self.file.flush()

    def close(self):
        self.file.close()


class LogBot(irc.IRCClient):
    """A logging IRC bot."""

    nickname = "twistedbot"

    def connectionMade(self):
        irc.IRCClient.connectionMade(self)
        self.logger = MessageLogger(open(self.factory.filename, "a"))
        self.logger.log("[connected at %s]" % 
                        time.asctime(time.localtime(time.time())))

    def connectionLost(self, reason):
        irc.IRCClient.connectionLost(self, reason)
        self.logger.log("[disconnected at %s]" % 
                        time.asctime(time.localtime(time.time())))
        self.logger.close()


    # callbacks for events

    def signedOn(self):
        """Called when bot has succesfully signed on to server."""
        self.join(self.factory.channel)

    def joined(self, channel):
        """This will get called when the bot joins the channel."""
        self.logger.log("[I have joined %s]" % channel)

    def privmsg(self, user, channel, msg):
        """This will get called when the bot receives a message."""
        user = user.split('!', 1)[0]
        self.logger.log("<%s> %s" % (user, msg))

        # Check to see if they're sending me a private message
        if channel == self.nickname:
            msg = "It isn't nice to whisper!  Play nice with the group."
            self.msg(user, msg)
            return

        # Otherwise check to see if it is a message directed at me
        if msg.startswith(self.nickname + ":"):
            msg = "%s: I am a log bot" % user
            self.msg(channel, msg)
            self.logger.log("<%s> %s" % (self.nickname, msg))

    def action(self, user, channel, msg):
        """This will get called when the bot sees someone do an action."""
        user = user.split('!', 1)[0]
        self.logger.log("* %s %s" % (user, msg))

    # irc callbacks

    def irc_NICK(self, prefix, params):
        """Called when an IRC user changes their nickname."""
        old_nick = prefix.split('!')[0]
        new_nick = params[0]
        self.logger.log("%s is now known as %s" % (old_nick, new_nick))


    # For fun, override the method that determines how a nickname is changed on
    # collisions. The default method appends an underscore.
    def alterCollidedNick(self, nickname):
        """
        Generate an altered version of a nickname that caused a collision in an
        effort to create an unused related name for subsequent registration.
        """
        return nickname + '^'


def aSillyBlockingMethod(self):
        import time
        while True:
            msg = raw_input()
            print msg



class LogBotFactory(protocol.ClientFactory):
    """A factory for LogBots.

    A new protocol instance will be created each time we connect to the server.
    """

    def __init__(self, channel, filename):
        self.channel = channel
        self.filename = filename

    def buildProtocol(self, addr):
        p = LogBot()
        p.factory = self
        return p

    def clientConnectionLost(self, connector, reason):
        """If we get disconnected, reconnect to server."""
        connector.connect()

    def clientConnectionFailed(self, connector, reason):
        print "connection failed:", reason
        reactor.stop()



if __name__ == '__main__':
    # initialize logging
    log.startLogging(sys.stdout)

    # create factory protocol and application
    f = LogBotFactory("#goon.squad.dev", "test.txt")

    # connect factory to this host and port
    reactor.connectTCP("irc.freenode.net", 6667, f)

    #Use this to keep user input open
    d = threads.deferToThread(aSillyBlockingMethod)

    # run bot
    reactor.run()

--TyrZaraki

1 回答

  • 3

    我知道我可能必须使用2个线程同时从服务器读取并同时输入,这是我可以实现的,但仅限于命令行输入 . 请注意,它仍在同时记录来自 Channels 的数据 .

    实际上,没有必要为此使用两个线程 . Twisted的一个主要优势是在不使用线程的情况下进行I / O. question and answer Michael linked to谈论Twisted的非线程支持,通过 twisted.internet.stdio.StandardIO 与标准输入和标准输出进行交互 .

    我的问题在于无法弄清楚如何通过从命令行输入和打印来改变这一点;能够实际向irc服务器发送消息供其他人阅读 .

    IRCClient 有一种向IRC服务器发送消息的方法 - 你问题中包含的示例代码甚至已经使用了这种方法, IRCClient.msg . 你需要做的就是打电话给它 .

    您的线程代码可能会像这样更改(再次,线程是不必要的,但为了显示如何从输入处理代码发送消息, just ,我将基于线程的这部分答案,以避免对代码的其他更改可能会使答案更难理解 . 您需要线程来执行此操作 . ):

    def aSillyBlockingMethod(bot):
        import time
        while True:
            msg = raw_input()
            bot.threadSafeMsg("#bottest", msg)
    
    
    class LogBot(irc.IRCClient):
        """A logging IRC bot."""
    
        nickname = "twistedbot"
    
        def connectionMade(self):
            irc.IRCClient.connectionMade(self)
            self.logger = MessageLogger(open(self.factory.filename, "a"))
            self.logger.log("[connected at %s]" % 
                            time.asctime(time.localtime(time.time())))
    
            # The bot is now connected.  Start reading input here.
            # Pass a reference to this protocol instance, so that
            # messages can be sent to this protocol instance.
            deferToThread(aSillyBlockingMethod, self)
    
    
        # Define a helper function for aSillyBlockingMethod to use.
        # Since aSillyBlockingMethod runs in a thread, it cannot just call
        # IRCClient.msg, since that method - like almost all methods in Twisted -
        # is not thread-safe.  Instead it must call this thread-safe wrapper.
        def threadSafeMsg(self, channel, message):
            reactor.callFromThread(self.msg, channel, message)
    

    请注意,这里发生的所有事情是 aSillyBlockingMethod 正在调用 LogBot 上的方法 . 使用 StandardIO 时,不需要线程安全包装,因为这样就不需要线程了 .

相关问题