summaryrefslogtreecommitdiffstats
path: root/Reaktor
diff options
context:
space:
mode:
Diffstat (limited to 'Reaktor')
-rwxr-xr-xReaktor/IRC/asybot.py163
-rw-r--r--Reaktor/IRC/getconf.py20
-rwxr-xr-xReaktor/IRC/index2
-rw-r--r--Reaktor/IRC/translate_colors.py2
-rw-r--r--Reaktor/TODO11
-rwxr-xr-xReaktor/commands/badcommand (renamed from Reaktor/commands/retard)0
-rwxr-xr-xReaktor/commands/caps1
-rwxr-xr-xReaktor/commands/say2
-rw-r--r--Reaktor/config.json28
9 files changed, 125 insertions, 104 deletions
diff --git a/Reaktor/IRC/asybot.py b/Reaktor/IRC/asybot.py
index 2cb533ea..ceebe844 100755
--- a/Reaktor/IRC/asybot.py
+++ b/Reaktor/IRC/asybot.py
@@ -15,40 +15,45 @@ from datetime import datetime as date, timedelta
import shlex
from time import sleep
from sys import exit
-from re import split, search
+from re import split, search, match
from textwrap import TextWrapper
import logging,logging.handlers
+from getconf import make_getconf
+getconf = make_getconf('config.json')
log = logging.getLogger('asybot')
hdlr = logging.handlers.SysLogHandler(facility=logging.handlers.SysLogHandler.LOG_DAEMON)
formatter = logging.Formatter( '%(filename)s: %(levelname)s: %(message)s')
hdlr.setFormatter(formatter)
log.addHandler(hdlr)
+logging.basicConfig(level = logging.DEBUG if getconf('main.debug') else logging.INFO)
# s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g -- removes color codes
class asybot(asychat):
- def __init__(self, server, port, nickname, targets, **kwargs):
+ def __init__(self):
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.server = getconf('irc.server')
+ self.port = getconf('irc.port')
+ self.channels = getconf('irc.channels')
+ self.realname = getconf('irc.nickname')
+ self.nickname = getconf('irc.nickname')
+ self.username = getconf('irc.nickname')
+ self.hostname = getconf('irc.nickname')
+ self.ircname = getconf('irc.nickname')
self.data = ''
- self.set_terminator('\r\n')
+ self.set_terminator('\r\n'.encode(encoding='UTF-8'))
self.create_socket(AF_INET, SOCK_STREAM)
self.connect((self.server, self.port))
self.wrapper = TextWrapper(subsequent_indent=" ",width=400)
+ log.info('=> irc://%s@%s:%s/%s' % (self.nickname, self.server, self.port, self.channels))
+
# When we don't receive data for alarm_timeout seconds then issue a
# PING every hammer_interval seconds until kill_timeout seconds have
# passed without a message. Any incoming message will reset alarm.
- self.alarm_timeout = 300
- self.hammer_interval = 10
+ self.alarm_timeout = getconf('irc.alarm_timeout')
+ self.hammer_interval = getconf('irc.hammer_interval')
self.kill_timeout = 360
signal(SIGALRM, lambda signum, frame: self.alarm_handler())
self.reset_alarm()
@@ -69,7 +74,7 @@ class asybot(asychat):
alarm(self.hammer_interval)
def collect_incoming_data(self, data):
- self.data += data
+ self.data += data.decode(encoding='UTF-8')
def found_terminator(self):
log.debug('<< %s' % self.data)
@@ -80,7 +85,6 @@ class asybot(asychat):
_, 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)
@@ -100,110 +104,65 @@ class asybot(asychat):
self.reset_alarm()
def push(self, message):
- log.debug('>> %s' % message)
- asychat.push(self, message + self.get_terminator())
+ msg = (message + self.get_terminator().decode(encoding='UTF-8')).encode(encoding='UTF-8')
+ log.debug('>> %s' % msg)
+ asychat.push(self, msg)
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))
+ self.push('JOIN %s' % ','.join(self.channels))
def on_privmsg(self, prefix, command, params, rest):
def PRIVMSG(text):
- for line in self.wrapper.wrap(text):
+ for line in self.wrapper.wrap(text.decode(encoding='UTF-8')):
msg = 'PRIVMSG %s :%s' % (','.join(params), line)
log.info(msg)
self.push(msg)
sleep(1)
def ME(text):
- PRIVMSG('ACTION ' + text + '')
+ PRIVMSG(('ACTION ' + text + '').encode(encoding='UTF-8'))
- _from = prefix.split('!', 1)[0]
+ for command in getconf('irc.commands'):
+ y = match(command['pattern'], rest)
+ if y:
+ self.execute_command(command, y, PRIVMSG, ME)
- 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
- from time import time
- Reaktor_dir = dirname(realpath(dirname(__file__)))
- public_commands = join(Reaktor_dir, 'public_commands')
- command = join(public_commands, _command)
-
- if is_executable(command):
-
- env = {}
- args = []
- start = time()
- if _argument != None:
- env['argument'] = _argument
- args = shlex.split(_argument)
- try:
- p = popen([command] + args,bufsize=1, stdout=PIPE, stderr=PIPE, env=env)
- except OSError, error:
- ME('brain damaged')
- log.error('OSError@%s: %s' % (command, error))
- return
- pid = p.pid
- for line in iter(p.stdout.readline,""):
- PRIVMSG(translate_colors(line))
- log.debug('%s stdout: %s' % (pid, line))
- p.wait()
- elapsed = time() - start
- code = p.returncode
- log.info('command: %s -> %s in %d seconds' % (command, code,elapsed))
- [log.debug('%s stderr: %s' % (pid, x)) for x in p.stderr.readlines()]
-
- if code != 0:
- ME('mimimi')
-
- else:
- if _handle != '*':
- PRIVMSG(_from + ': you are made of stupid')
+ def execute_command(self, command, match, PRIVMSG, ME):
+ from os.path import realpath, dirname, join
+ from subprocess import Popen as popen, PIPE
+ from time import time
-
-# 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]
+ #TODO: allow only commands below ./commands/
+ exe = join(dirname(realpath(dirname(__file__))), command['argv'][0])
+ myargv = [exe] + command['argv'][1:]
+ env = {}
+ start = time()
+ try:
+ p = popen(myargv, bufsize=1, stdout=PIPE, stderr=PIPE, env=env)
+ except (OSError, Exception) as error:
+ ME('brain damaged')
+ log.error('OSError@%s: %s' % (myargv, error))
+ return
+ pid = p.pid
+ for line in iter(p.stdout.readline, ''.encode(encoding='UTF-8')):
+ try:
+ PRIVMSG(translate_colors(line))
+ except Exception as error:
+ log.error('no send: %s' % error)
+ log.debug('%s stdout: %s' % (pid, line))
+ p.wait()
+ elapsed = time() - start
+ code = p.returncode
+ log.info('command: %s -> %s in %d seconds' % (myargv, code, elapsed))
+ [log.debug('%s stderr: %s' % (pid, x)) for x in p.stderr.readlines()]
+
+ if code != 0:
+ ME('mimimi')
+
if __name__ == "__main__":
- from os import environ as env
-
- lol = logging.DEBUG if env.get('debug',False) else logging.INFO
- logging.basicConfig(level=lol)
- try:
- name = getconf1('Name', '/etc/tinc/retiolum/tinc.conf')
- hostname = '%s.retiolum' % name
- except:
- name = gethostname()
- hostname = 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'))
- log.info('=> 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)
-
+ asybot()
loop()
diff --git a/Reaktor/IRC/getconf.py b/Reaktor/IRC/getconf.py
new file mode 100644
index 00000000..5fdd1cdb
--- /dev/null
+++ b/Reaktor/IRC/getconf.py
@@ -0,0 +1,20 @@
+#getconf = make_getconf("dateiname.json")
+#getconf(key) -> value
+#oder error
+
+import json
+
+def make_getconf(filename):
+ def getconf(prop):
+ prop_split = prop.split('.')
+ string = ''
+ file = open(filename)
+ for line in file.readlines():
+ string+=line
+ parsed = json.loads(string)
+ tmp = parsed
+ for pr in prop_split:
+ tmp = tmp[pr]
+
+ return tmp
+ return getconf
diff --git a/Reaktor/IRC/index b/Reaktor/IRC/index
index cc2652fe..2dc803a1 100755
--- a/Reaktor/IRC/index
+++ b/Reaktor/IRC/index
@@ -3,4 +3,4 @@ set -xeuf
# cd //Reaktor
cd $(dirname $(readlink -f $0))/..
-host=irc.freenode.net target='#krebs' python IRC/asybot.py "$@"
+exec IRC/asybot.py "$@"
diff --git a/Reaktor/IRC/translate_colors.py b/Reaktor/IRC/translate_colors.py
index bd716618..3ea34be6 100644
--- a/Reaktor/IRC/translate_colors.py
+++ b/Reaktor/IRC/translate_colors.py
@@ -23,7 +23,7 @@ COLOR_MAP = {
}
def translate_colors (line):
for color,replace in COLOR_MAP.items():
- line = line.replace(color,replace)
+ line = line.replace(color.encode(encoding='UTF-8'),replace.encode(encoding='UTF-8'))
return line
if __name__ == "__main__":
diff --git a/Reaktor/TODO b/Reaktor/TODO
new file mode 100644
index 00000000..6dbc2f8d
--- /dev/null
+++ b/Reaktor/TODO
@@ -0,0 +1,11 @@
+{ "pattern": "^(?:asybot|\\*):.*", "argv": [ "commands/say", "{{from.nickname}}: you are made of stupid" ], only_match: true }
+
+getconf: check syntax and semantics on load
+getconf: reload inotify
+
+apropros caps: commands need access to config
+
+commands need access to from (eg as env var):
+ _from = prefix.split('!', 1)[0]
+
+provide arguments to commands
diff --git a/Reaktor/commands/retard b/Reaktor/commands/badcommand
index c59b4d1c..c59b4d1c 100755
--- a/Reaktor/commands/retard
+++ b/Reaktor/commands/badcommand
diff --git a/Reaktor/commands/caps b/Reaktor/commands/caps
index bc3d7ba2..caa1fe06 100755
--- a/Reaktor/commands/caps
+++ b/Reaktor/commands/caps
@@ -1,4 +1,5 @@
#! /bin/sh
+exec echo 'TODO: need access to config.json'
set -euf
cd public_commands
echo `ls`
diff --git a/Reaktor/commands/say b/Reaktor/commands/say
new file mode 100755
index 00000000..8b83c056
--- /dev/null
+++ b/Reaktor/commands/say
@@ -0,0 +1,2 @@
+#!/bin/sh
+printf '%s\n' "$*"
diff --git a/Reaktor/config.json b/Reaktor/config.json
new file mode 100644
index 00000000..7b84c55e
--- /dev/null
+++ b/Reaktor/config.json
@@ -0,0 +1,28 @@
+{
+ "main": {
+ "debug": true,
+ "name": "asybot"
+ },
+ "irc": {
+ "alarm_timeout": 300,
+ "hammer_interval": 10,
+ "kill_timeout": 360,
+ "nickname": "asybot",
+ "server": "irc.freenode.org",
+ "port": 6667,
+ "channels": [
+ "#krebs"
+ ],
+ "commands": [
+ { "pattern": "^(?:asybot|\\*):\\s*caps\\s*$", "argv": [ "commands/caps" ] },
+ { "pattern": "^(?:asybot|\\*):\\s*hello\\s*$", "argv": [ "commands/hello" ] },
+ { "pattern": "^(?:asybot|\\*):\\s*reload\\s*$", "argv": [ "commands/reload" ] },
+ { "pattern": "^(?:asybot|\\*):\\s*badcommand\\s*$", "argv": [ "commands/badcommand" ] },
+ { "pattern": "^(?:asybot|\\*):\\s*rev\\s*$", "argv": [ "commands/rev" ] },
+ { "pattern": "^(?:asybot|\\*):\\s*uptime\\s*$", "argv": [ "commands/uptime" ] },
+ { "pattern": "^(?:asybot|\\*):\\s*nocommand\\s*$", "argv": [ "commands/nocommand" ] },
+ { "pattern": "^.*\\basybot(?:\\b[^:].*)?$", "argv": [ "commands/say", "I'm famous" ] }
+ ]
+ }
+}
+