こんにちは! もう一人の sasaki-k です。 以前からpythonの twisted でなにか作ってみようと思っていたので、技術の無駄遣いネタとして 「常駐型IRCプロキシサーバ」を作ってみました。 バッチプログラムからIRCへ何度も発言させようとすると下のように都度joinとquitしてしまい、 「邪魔だなあ」と言われることが多かったのが背景です。
23:02 *hoge-bot join #channel (~hoge-bot@xxxx.klab.jp) (発言) 23:02 *hoge-bot quit (Remote host closed the connection) 23:02 *hoge-bot join #channel (~hoge-bot@xxxx.klab.jp) (次の発言) 23:02 *hoge-bot quit (Remote host closed the connection)
そこで、twistedに付属しているIRCのクライアントを改造して、サーバソケットで 外部プログラムから発言したいメッセージを受け付けられるようにしてみました。ソケットサーバ兼IRCクライアントです。 このpythonスクリプトをバッチの最初で起動しておいて、所定のListenポートに発言したい内容を Socketクライアントから流しこめば発言してくれる、という流れです。 あるいはdaemontools などでこのスクリプトを常駐させておくのもよさそうです。 使った環境は Twisted 10.1.0 python 2.5.2 です。

# vim: fileencoding=utf-8

"""
Announce irc bot.
"""

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

# system imports
import sys

class IrcBotClient(irc.IRCClient):
    """
    IRCに接続する側のprotocolです。接続するとfactoryのprotocolを差し替えます。
    """    
    nickname = "announce-bot"

    def connectionMade(self):
        irc.IRCClient.connectionMade(self)
        self.factory.protocol = self

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

class IrcBotFactory(protocol.ClientFactory):
    """
    IRCに接続する側のprotocolのfactoryです。
    """
    protocol = IrcBotClient

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

    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()

class IrcBotCommander(protocol.Protocol):
    """
    メッセージ送信プログラムからの文字列を受け取ります(utf-8固定)
    """
    def dataReceived(self, data):
        channel = "#" + self.factory.botFactory.channel
        data = unicode(data, 'utf-8')
        data = data.rstrip()
        data = data.encode('iso-2022-jp')
        self.factory.botFactory.protocol.msg(channel, data)
        self.transport.loseConnection()

class IrcBotCommanderFactory(protocol.ServerFactory):
    """
    メッセージ送信プログラムのfactoryです。IrcBotへのポインタを持ちます
    """
    protocol = IrcBotCommander

    def __init__(self, botFactory):
        self.botFactory = botFactory

# main
if __name__ == '__main__':
    # initialize logging
    log.startLogging(sys.stdout)
    
    ircBotFactory = IrcBotFactory(sys.argv[1])
    ircBotCommanderFactory = IrcBotCommanderFactory(ircBotFactory)

    # xxx.xxx.xxxはircサーバ
    reactor.connectTCP("xxx.xxx.xxx", 6667, ircBotFactory) 
    reactor.listenTCP(12345, ircBotCommanderFactory)

    # run bot
    reactor.run()


おかげで絶え間なく(?) 発言できるようになりましたー
23:02 *announce-bot join #channel (~hoge-bot@xxxx.klab.jp) 23:02 (announce-bot) ああああ 23:03 (announce-bot) <-------------- テストテスト --------------> 23:10 (announce-bot) <-------------- これからよろしくね -------------->
今後複数チャンネル対応とか、他の人の発言に対応した動きをするとか、できたらいいなと思ってます。