From 97009ab8d2ecbe79a7474adb8a6537102731bc39 Mon Sep 17 00:00:00 2001 From: Jan Philipp Timme Date: Wed, 14 May 2014 19:38:19 +0200 Subject: [PATCH] [TASK] Initial import. --- .gitignore | 2 + Makefile | 2 + monitor/__init__.py | 0 monitor/bot.py | 64 ++++++++++++++++++++ requirements.txt | 3 + settings.ini | 8 +++ twisted/plugins/monitorbot_plugin.py | 90 ++++++++++++++++++++++++++++ 7 files changed, 169 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 monitor/__init__.py create mode 100644 monitor/bot.py create mode 100644 requirements.txt create mode 100644 settings.ini create mode 100644 twisted/plugins/monitorbot_plugin.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7f3ba45 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.pyc +*.cache diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..97c8419 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +run: + twistd -n monitorbot diff --git a/monitor/__init__.py b/monitor/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/monitor/bot.py b/monitor/bot.py new file mode 100644 index 0000000..6653252 --- /dev/null +++ b/monitor/bot.py @@ -0,0 +1,64 @@ +from twisted.internet import protocol +from twisted.python import log +from twisted.words.protocols import irc + + +class MonitorBot(irc.IRCClient): + def connectionMade(self): + """Called when a connection is made.""" + self.nickname = self.factory.nickname + self.realname = self.factory.realname + irc.IRCClient.connectionMade(self) + log.msg("connectionMade") + + def connectionLost(self, reason): + """Called when a connection is lost.""" + irc.IRCClient.connectionLost(self, reason) + log.msg("connectionLost {!r}".format(reason)) + + # callbacks for events + + def signedOn(self): + """Called when bot has successfully signed on to server.""" + log.msg("Signed on") + if self.nickname != self.factory.nickname: + log.msg('Your nickname was already occupied, actual nickname is "{}".'.format(self.nickname)) + self.join(self.factory.channel) + + def joined(self, channel): + """Called when the bot joins the channel.""" + log.msg("[{nick} has joined {channel}]".format(nick=self.nickname, channel=self.factory.channel,)) + + def privmsg(self, user, channel, msg): + """Called when the bot receives a message.""" + sendTo = None + prefix = '' + senderNick = user.split('!', 1)[0] + if channel == self.nickname: + # Reply back in the query / privmsg + sendTo = senderNick + elif msg.startswith(self.nickname): + # Reply back on the channel + sendTo = channel + prefix = senderNick + ': ' #Mark message so people know what is going on + else: + msg = msg.lower() + if msg in ['!hi']: + sendTo = channel + prefix = senderNick + ': ' + if sendTo: + reply = "Hello." + self.msg(sendTo, prefix + reply) + log.msg( + "sent message to {receiver}, triggered by {sender}:\n\t{reply}" + .format(receiver=sendTo, sender=senderNick, reply=reply) + ) + +class MonitorBotFactory(protocol.ClientFactory): + protocol = MonitorBot + + def __init__(self, channel, nickname, realname): + """Initialize the bot factory with our settings.""" + self.channel = channel + self.nickname = nickname + self.realname = realname diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b8644b3 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +coverage +pyopenssl +twisted diff --git a/settings.ini b/settings.ini new file mode 100644 index 0000000..fe8cb79 --- /dev/null +++ b/settings.ini @@ -0,0 +1,8 @@ +[irc] +endpoint = tcp:host=irc.euirc.net:port=6667 +nickName = ftpd +realName = bot: provides tracking of an ftp +channel = #Tonari. + +[fsmonitor] +path=/home/kuzuru-ftp/ diff --git a/twisted/plugins/monitorbot_plugin.py b/twisted/plugins/monitorbot_plugin.py new file mode 100644 index 0000000..72e7e3b --- /dev/null +++ b/twisted/plugins/monitorbot_plugin.py @@ -0,0 +1,90 @@ +from ConfigParser import ConfigParser + +from twisted.application.service import IServiceMaker, Service +from twisted.internet.endpoints import clientFromString +from twisted.plugin import IPlugin +from twisted.python import usage, log +from zope.interface import implementer + +from twisted.internet import inotify +from twisted.python import filepath + +from monitor.bot import MonitorBotFactory + +class MonitorBotService(Service): + _bot = None + + def __init__(self, endpoint, channel, nickname, realname, path): + self._endpoint = endpoint + self._channel = channel + self._nickname = nickname + self._realname = realname + self._path = path + + def startService(self): + """Construct a client & connect to server.""" + from twisted.internet import reactor + + """Define callbacks.""" + def connected(bot): + self._bot = bot + + def failure(err): + log.err(err, _why='Could not connect to specified server.') + reactor.stop() + + client = clientFromString(reactor, self._endpoint) + factory = MonitorBotFactory( + self._channel, + self._nickname, + self._realname + ) + + def fsnotify(ignored, filepath, mask): + msg = "event %s on %s" % (', '.join(inotify.humanReadableMask(mask)), filepath) + self._bot.msg(self._channel, msg) + pass + + notifier = inotify.INotify() + notifier.startReading() + notifier.watch(filepath.FilePath(self._path), autoAdd=True, recursive=True, callbacks=[fsnotify]) + + """Attach defined callbacks.""" + return client.connect(factory).addCallbacks(connected, failure) + + def stopService(self): + """Disconnect.""" + if self._bot and self._bot.transport.connected: + self._bot.transport.loseConnection() + + +class Options(usage.Options): + optParameters = [ + ['config', 'c', 'settings.ini', 'Configuration file.'], + ] + + +@implementer(IServiceMaker, IPlugin) +class BotServiceMaker(object): + tapname = "monitorbot" + description = "IRC bot that provides verbose monitoring of an fs path." + options = Options + + def makeService(self, options): + """Read the config and construct the monitorbot service.""" + config = ConfigParser() + config.read([options['config']]) + + return MonitorBotService( + endpoint=config.get('irc', 'endpoint'), + channel=config.get('irc', 'channel'), + nickname=config.get('irc', 'nickname'), + realname=config.get('irc', 'realname'), + path=config.get('fsmonitor', 'path'), + ) + +# Now construct an object which *provides* the relevant interfaces +# The name of this variable is irrelevant, as long as there is *some* +# name bound to a provider of IPlugin and IServiceMaker. + +serviceMaker = BotServiceMaker()