aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@iiso>2011-09-13 17:04:45 +0200
committertv <tv@iiso>2011-09-13 17:04:45 +0200
commit7fb86be4b75f7c1a53e5ee39b620a52f2d35d1bf (patch)
treec47bc370c268fa630bc2672cab8b1f1ef63ef26e
parent8ed75e6eaf2b5050477b644a1bb97e0c182a4260 (diff)
//Reaktor/IRC: replace irclib with own async bot
Unfortunately irclib failed to detect stale connections. Asyboy comes to the rescue (maybe).^_^->deal with it...^_^
-rwxr-xr-xIRC/asybot.py169
-rwxr-xr-xIRC/bot.py34
-rwxr-xr-xIRC/bot2.py130
-rw-r--r--IRC/content1
-rwxr-xr-xIRC/index2
-rwxr-xr-xIRC/install28
-rw-r--r--README.md11
-rwxr-xr-xinstall6
8 files changed, 174 insertions, 207 deletions
diff --git a/IRC/asybot.py b/IRC/asybot.py
new file mode 100755
index 0000000..6e9df1d
--- /dev/null
+++ b/IRC/asybot.py
@@ -0,0 +1,169 @@
+#! /usr/bin/env python
+#
+# //Reaktor/IRC/asybot.py
+#
+
+from __future__ import print_function
+
+def is_executable(x):
+ import os
+ return os.path.exists(x) and os.access(x, os.X_OK)
+
+from asynchat import async_chat as asychat
+from asyncore import loop
+from socket import AF_INET, SOCK_STREAM
+from signal import SIGALRM, signal, alarm
+from datetime import datetime as date, timedelta
+from sys import exit
+from re import split, search
+class asybot(asychat):
+ def __init__(self, server, port, nickname, targets, **kwargs):
+ asychat.__init__(self)
+ self.server = server
+ self.port = port
+ self.nickname = nickname
+ self.targets = targets
+ self.username = kwargs['username'] if 'username' in kwargs else nickname
+ self.hostname = kwargs['hostname'] if 'hostname' in kwargs else nickname
+ self.ircname = kwargs['ircname'] if 'ircname' in kwargs else nickname
+ self.realname = kwargs['realname'] if 'realname' in kwargs else nickname
+ self.data = ''
+ self.set_terminator('\r\n')
+ self.create_socket(AF_INET, SOCK_STREAM)
+ self.connect((self.server, self.port))
+ self.alarm_timeout = 300
+ self.kill_timeout = 360
+ self.last_activity = date.now()
+ signal(SIGALRM, lambda signum, frame: self.alarm_handler())
+ alarm(self.alarm_timeout)
+ loop()
+
+ def alarm_handler(self):
+ delta = date.now() - self.last_activity
+ if delta > timedelta(seconds=self.kill_timeout):
+ print('kill alarm %s' % delta)
+ exit()
+ else:
+ print('alarm %s' % delta)
+ self.push('PING :asybot')
+ alarm(self.alarm_timeout)
+
+ def collect_incoming_data(self, data):
+ self.data += data
+
+ def found_terminator(self):
+ print('< %s' % self.data)
+ self.last_activity = date.now()
+
+ message = self.data
+ self.data = ''
+
+ _, prefix, command, params, rest, _ = \
+ split('^(?::(\S+)\s)?(\S+)((?:\s[^:]\S*)*)(?:\s:(.*))?$', message)
+ params = params.split(' ')[1:]
+ #print([prefix, command, params, rest])
+
+ if command == 'PING':
+ self.push('PONG :%s' % rest)
+
+ elif command == 'PRIVMSG':
+ self.on_privmsg(prefix, command, params, rest)
+
+ # reset alarm
+ alarm(self.alarm_timeout)
+
+ def push(self, message):
+ print('> %s' % message)
+ asychat.push(self, message + self.get_terminator())
+
+ def handle_connect(self):
+ self.push('NICK %s' % self.nickname)
+ self.push('USER %s %s %s :%s' %
+ (self.username, self.hostname, self.server, self.realname))
+ self.push('JOIN %s' % ','.join(self.targets))
+
+ def on_privmsg(self, prefix, command, params, rest):
+ def PRIVMSG(text):
+ self.push('PRIVMSG %s :%s' % (','.join(params), text))
+
+ def ME(text):
+ PRIVMSG('ACTION ' + text + '')
+
+ _from = prefix.split('!', 1)[0]
+
+ try:
+ _, _handle, _command, _argument, _ = split(
+ '^(\w+|\*):\s*(\w+)(?:\s+(.*))?$', rest)
+ except ValueError, error:
+ if search(self.nickname, rest):
+ PRIVMSG('I\'m so famous')
+ return # ignore
+
+ if _handle == self.nickname or _handle == '*':
+
+ from os.path import realpath, dirname, join
+ from subprocess import Popen as popen, PIPE
+
+ Reaktor_dir = dirname(realpath(dirname(__file__)))
+ public_commands = join(Reaktor_dir, 'public_commands')
+ command = join(public_commands, _command)
+
+ if is_executable(command):
+
+ env = {}
+ if _argument != None:
+ env['argument'] = _argument
+
+ try:
+ p = popen([command], stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env)
+ except OSError, error:
+ ME('is made of stupid')
+ print('OSError@%s: %s' % (command, error))
+ return
+
+ stdout, stderr = [ x[:len(x)-1] for x in
+ [ x.split('\n') for x in p.communicate()]]
+ code = p.returncode
+ pid = p.pid
+
+ print('command: %s -> %s' % (command, code))
+ [print('%s stdout: %s' % (pid, x)) for x in stdout]
+ [print('%s stderr: %s' % (pid, x)) for x in stderr]
+
+ if code == 0:
+ [PRIVMSG(x) for x in stdout]
+ [PRIVMSG(x) for x in stderr]
+ else:
+ ME('mimimi')
+
+ else:
+ if _handle != '*':
+ PRIVMSG(_from + ': you are made of stupid')
+
+# retrieve the value of a [singleton] variable from a tinc.conf(5)-like file
+def getconf1(x, path):
+ from re import findall
+ pattern = '(?:^|\n)\s*' + x + '\s*=\s*(.*\w)\s*(?:\n|$)'
+ y = findall(pattern, open(path, 'r').read())
+ if len(y) < 1:
+ raise AttributeError("len(getconf1('%s', '%s') < 1)" % (x, path))
+ if len(y) > 1:
+ y = ' '.join(y)
+ raise AttributeError("len(getconf1('%s', '%s') > 1)\n ====> %s"
+ % (x, path, y))
+ return y[0]
+
+if __name__ == "__main__":
+ from os import environ as env
+ name = getconf1('Name', '/etc/tinc/retiolum/tinc.conf')
+ hostname = '%s.retiolum' % name
+ nick = str(env.get('nick', name))
+ host = str(env.get('host', 'supernode'))
+ port = int(env.get('port', 6667))
+ target = str(env.get('target', '#retiolum'))
+ print('====> irc://%s@%s:%s/%s' % (nick, host, port, target))
+
+ from getpass import getuser
+ asybot(host, port, nick, [target], username=getuser(),
+ ircname='//Reaktor running at %s' % hostname,
+ hostname=hostname)
diff --git a/IRC/bot.py b/IRC/bot.py
deleted file mode 100755
index af974f4..0000000
--- a/IRC/bot.py
+++ /dev/null
@@ -1,34 +0,0 @@
-#! /usr/bin/env python2
-
-from irclib import IRC, ServerConnectionError, is_channel
-from sys import exit
-from os import environ as env
-
-host = str(env.get('host', 'irc.freenode.org'))
-port = int(env.get('port', 6667))
-nick = str(env.get('nick', 'crabspasm'))
-channel = str(env.get('channel', '#tincspasm'))
-print '====> irc://%s@%s:%s/%s' % (nick, host, port, channel)
-
-irc = IRC()
-try:
- client = irc.server().connect(host, port, nick)
-except ServerConnectionError, error:
- print error
- exit
-
-def on_connect(connection, event):
- connection.join(channel)
- print 'Es passiert...'
-
-def on_join(connection, event):
- connection.privmsg(channel, 'lol')
-
-def on_disconnect(connection, event):
- exit
-
-client.add_global_handler('welcome', on_connect)
-client.add_global_handler('join', on_join)
-client.add_global_handler('disconnect', on_disconnect)
-
-irc.process_forever()
diff --git a/IRC/bot2.py b/IRC/bot2.py
deleted file mode 100755
index 326dd8f..0000000
--- a/IRC/bot2.py
+++ /dev/null
@@ -1,130 +0,0 @@
-#! /usr/bin/env python
-#
-# //Reaktor/IRC/bot2.py
-#
-
-from __future__ import print_function
-from irclib import SimpleIRCClient, ServerConnectionError, is_channel
-from sys import exit
-from os import environ as env
-import re
-
-class IRCBot(SimpleIRCClient):
- def __init__(self, target):
- SimpleIRCClient.__init__(self)
- self.target = target
-
- def on_pubmsg(self, connection, event):
-
- def PRIVMSG(target, text):
- self.connection.privmsg(target, text)
-
- def ME(target, text):
- PRIVMSG(target, 'ACTION ' + text + '')
-
- def is_executable(x):
- import os
- return os.path.exists(x) and os.access(x, os.X_OK)
-
- _nickname = connection.get_nickname()
- _source = event.source()
- _from = _source.split('!', 1)[0]
- _target = event.target()
-
- try:
- _, _handle, _command, _argument, _ = re.split(
- '^(\w+|\*):\s*(\w+)(?:\s+(.*))?$', event.arguments()[0])
- except ValueError, error:
- if re.search(_nickname, event.arguments()[0]):
- PRIVMSG(self.target, 'I\'m so famous')
- return # ignore
-
- if _handle == _nickname or _handle == '*':
-
- from os.path import realpath, dirname, join
- from subprocess import Popen as popen, PIPE
-
- Reaktor_dir = dirname(realpath(dirname(__file__)))
- public_commands = join(Reaktor_dir, 'public_commands')
- command = join(public_commands, _command)
-
- if is_executable(command):
-
- env = {}
- if _argument != None:
- env['argument'] = _argument
-
- try:
- p = popen([command], stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env)
- except OSError, error:
- ME(self.target, 'is made of stupid')
- print('OSError@%s: %s' % (command, error))
- return
-
- stdout, stderr = [ x[:len(x)-1] for x in
- [ x.split('\n') for x in p.communicate()]]
- code = p.returncode
- pid = p.pid
-
- print('command: %s -> %s' % (command, code))
- [print('%s stdout: %s' % (pid, x)) for x in stdout]
- [print('%s stderr: %s' % (pid, x)) for x in stderr]
-
- if code == 0:
- [PRIVMSG(self.target, x) for x in stdout]
- [PRIVMSG(_source, x) for x in stderr]
- else:
- ME(self.target, 'mimimi')
-
- else:
- if _handle != '*':
- PRIVMSG(self.target, _from + ': you are made of stupid')
-
- def on_welcome(self, connection, event):
- print('I\'m welcome! :D joining to %s now...' % (self.target))
- if is_channel(self.target):
- connection.join(self.target)
- else:
- self.connection.privmsg(self.target, 'lol')
- self.connection.quit('Pong timeout: 423 seconds')
-
- def on_join(self, connection, event):
- print('Es passiert in %s' % (self.target))
-
- def on_disconnect(self, connection, event):
- # TODO reconnect
- exit(0)
-
-# retrieve the value of a [singleton] variable from a tinc.conf(5)-like file
-def getconf1(x, path):
- from re import findall
- pattern = '(?:^|\n)\s*' + x + '\s*=\s*(.*\w)\s*(?:\n|$)'
- y = findall(pattern, open(path, 'r').read())
- if len(y) < 1:
- raise AttributeError("len(getconf1('%s', '%s') < 1)" % (x, path))
- if len(y) > 1:
- y = ' '.join(y)
- raise AttributeError("len(getconf1('%s', '%s') > 1)\n ====> %s"
- % (x, path, y))
- return y[0]
-
-def main():
- name = getconf1('Name', '/etc/tinc/retiolum/tinc.conf')
- nick = str(env.get('nick', name))
- host = str(env.get('host', 'supernode'))
- port = int(env.get('port', 6667))
- target = str(env.get('target', '#retiolum'))
- print('====> irc://%s@%s:%s/%s' % (nick, host, port, target))
-
- client = IRCBot(target)
- try:
- from getpass import getuser
- client.connect(host, port, nick, username=getuser(),
- ircname='//Reaktor running at %s.retiolum' % (name))
- except ServerConnectionError, error:
- print(error)
- exit(1)
- client.start()
-
-if __name__ == "__main__":
- main()
diff --git a/IRC/content b/IRC/content
deleted file mode 100644
index e029237..0000000
--- a/IRC/content
+++ /dev/null
@@ -1 +0,0 @@
-python-irclib-0.4.6/ircbot.py
diff --git a/IRC/index b/IRC/index
index 68b6cf3..7b51632 100755
--- a/IRC/index
+++ b/IRC/index
@@ -6,4 +6,4 @@ cd $(dirname $(readlink -f $0))/..
IRC/install
-exec python IRC/bot2.py "$@"
+exec python IRC/asybot.py "$@"
diff --git a/IRC/install b/IRC/install
deleted file mode 100755
index d5f7a8c..0000000
--- a/IRC/install
+++ /dev/null
@@ -1,28 +0,0 @@
-#! /bin/sh
-set -xeuf
-
-# cd //Reaktor/IRC
-cd $(dirname $(readlink -f $0))
-
-# install irclib.py
-{
- PV=0.4.6
- PN=python-irclib
- P=$PN-$PV
- tarball=$P.tar.gz
- URL=http://downloads.sourceforge.net/$PN/$tarball
- SHA1SUM=c6271e44293ed51c21af0f44ce106667d3006e6f
-
- file=irclib.py
-
- if ! echo "$SHA1SUM $file" | sha1sum -c; then
- temp=`mktemp`
- trap "rm -f $temp" EXIT INT
-
- echo $P/$file > $temp
- curl -LfsS $URL | tar --strip-components=1 -zxT $temp
- fi
- echo "$SHA1SUM $file" | sha1sum -c
-}
-
-
diff --git a/README.md b/README.md
index 05af8ef..b6ea89f 100644
--- a/README.md
+++ b/README.md
@@ -2,22 +2,19 @@
## Quickstart
- ## 1. prepare Reaktor
- //Reaktor/install
-
- ## 2. create a dedicated user
+ ## 1. create a dedicated user
useradd Reaktor
- ## 3. marry Reaktor with /sbin/init
+ ## 2. marry Reaktor with /sbin/init
- ## 3a. /etc/inittab-like foo
+ ## 2a. /etc/inittab-like foo
echo 10:2345:respawn:/bin/su Reaktor -c /krebs/Reaktor/index >>/etc/inittab
# or 10:2345:respawn:/usr/bin/sudo -u Reaktor /krebs/Reaktor/index
# if Reaktor's shell is /bin/false or similar
# [check with e.g getent passwd Reaktor]
telinit q
- ## 3b. upstart-like foo
+ ## 2b. upstart-like foo
cat > /etc/init/Reaktor.conf <<EOF
description "Krebs Reaktor"
diff --git a/install b/install
deleted file mode 100755
index 761bc43..0000000
--- a/install
+++ /dev/null
@@ -1,6 +0,0 @@
-#! /bin/sh
-set -euf
-
-cd $(dirname $(readlink -f $0))
-
-exec IRC/install