aboutsummaryrefslogtreecommitdiffstats
path: root/reaktor
diff options
context:
space:
mode:
Diffstat (limited to 'reaktor')
-rw-r--r--reaktor/__init__.py2
-rwxr-xr-xreaktor/commands/caps18
-rwxr-xr-xreaktor/commands/identify27
-rwxr-xr-xreaktor/commands/licht_resolver53
-rwxr-xr-xreaktor/commands/taken4
-rwxr-xr-xreaktor/commands/version14
-rw-r--r--reaktor/config.py175
-rwxr-xr-xreaktor/core.py294
-rw-r--r--reaktor/getconf.py14
-rw-r--r--reaktor/ircasy.py380
-rw-r--r--reaktor/translate_colors.py53
11 files changed, 533 insertions, 501 deletions
diff --git a/reaktor/__init__.py b/reaktor/__init__.py
index 0d03ee7..dd9b22c 100644
--- a/reaktor/__init__.py
+++ b/reaktor/__init__.py
@@ -1 +1 @@
-__version__="0.5.1"
+__version__ = "0.5.1"
diff --git a/reaktor/commands/caps b/reaktor/commands/caps
index b5d6642..6f26540 100755
--- a/reaktor/commands/caps
+++ b/reaktor/commands/caps
@@ -2,12 +2,18 @@
import imp
import os
+
def load_config(filename):
- dirname = os.path.dirname(filename)
- modname, ext = os.path.splitext(os.path.basename(filename))
- file, pathname, description = imp.find_module(modname, [ dirname ])
- return imp.load_module(modname, file, pathname, description)
+ dirname = os.path.dirname(filename)
+ modname, ext = os.path.splitext(os.path.basename(filename))
+ file, pathname, description = imp.find_module(modname, [dirname])
+ return imp.load_module(modname, file, pathname, description)
+
config = load_config(os.environ['config_filename'])
-print('Private: '+' '.join(filter(None,[ x.get('capname',None) for x in config.commands])))
-print('Public: '+' '.join(filter(None,[ x.get('capname',None) for x in config.public_commands])))
+print('Private: '+' '.join(filter(
+ None, [x.get('capname', None) for x in config.commands]
+)))
+print('Public: '+' '.join(filter(
+ None, [x.get('capname', None) for x in config.public_commands]
+)))
diff --git a/reaktor/commands/identify b/reaktor/commands/identify
index c2fb2c5..9cb5726 100755
--- a/reaktor/commands/identify
+++ b/reaktor/commands/identify
@@ -1,22 +1,25 @@
#!/usr/bin/env python
import imp
-import os,sys
+import os
+import sys
+
def load_config(filename):
- dirname = os.path.dirname(filename)
- modname, ext = os.path.splitext(os.path.basename(filename))
- file, pathname, description = imp.find_module(modname, [ dirname ])
- return imp.load_module(modname, file, pathname, description)
+ dirname = os.path.dirname(filename)
+ modname, ext = os.path.splitext(os.path.basename(filename))
+ file, pathname, description = imp.find_module(modname, [dirname])
+ return imp.load_module(modname, file, pathname, description)
+
config = load_config(os.environ['config_filename'])
with open(config.admin_file) as f:
- for line in f:
- nick,secret = line.split()
- if sys.argv[1] == secret:
- print("identified you as %s!"%nick)
- with open(config.auth_file,'a+') as g:
- g.write(os.environ['_prefix'] +"\n")
- sys.exit(0)
+ for line in f:
+ nick, secret = line.split()
+ if sys.argv[1] == secret:
+ print("identified you as %s!" % nick)
+ with open(config.auth_file, 'a+') as g:
+ g.write(os.environ['_prefix'] + "\n")
+ sys.exit(0)
print("unable to identify you, sorry")
diff --git a/reaktor/commands/licht_resolver b/reaktor/commands/licht_resolver
index 90d06c8..c86243e 100755
--- a/reaktor/commands/licht_resolver
+++ b/reaktor/commands/licht_resolver
@@ -1,37 +1,36 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
+import json
+from os import environ as env
+from struct import unpack
map = {
- 'shackspace': {
- 'device': {
- 0: 'Licht0, Zickenzone; Fenster',
- 1: 'Licht1, Sofaecke; Fenster',
- 2: 'Licht2, Zickenzone; Ghetto',
- 3: 'Licht3, Sofaecke; Ghetto',
- 4: 'Licht4, Richtung Getränkelager',
- 5: 'Licht5, Porschekonsole',
- 6: 'Licht6, Tomatenecke',
- 7: 'Licht7, Ghetto',
- 10: 'Hauptschalter'
- },
- 'state': {
- 0: 'aus',
- 1: 'an',
- 2: 'aus in T-10s'
- },
- '->': 'ist'
- }
+ 'shackspace': {
+ 'device': {
+ 0: 'Licht0, Zickenzone; Fenster',
+ 1: 'Licht1, Sofaecke; Fenster',
+ 2: 'Licht2, Zickenzone; Ghetto',
+ 3: 'Licht3, Sofaecke; Ghetto',
+ 4: 'Licht4, Richtung Getränkelager',
+ 5: 'Licht5, Porschekonsole',
+ 6: 'Licht6, Tomatenecke',
+ 7: 'Licht7, Ghetto',
+ 10: 'Hauptschalter'
+ },
+ 'state': {
+ 0: 'aus',
+ 1: 'an',
+ 2: 'aus in T-10s'
+ },
+ '->': 'ist'
+ }
}
-from struct import unpack
-import json
-from os import environ as env
-
location = "shackspace"
map = map[location]
-print (env["payload"]+"")
-did, sid= unpack('BB', json.loads(env['payload']))
-device,state = map['device'][did], map['state'][sid]
+print(env["payload"]+"")
+did, sid = unpack('BB', json.loads(env['payload']))
+device, state = map['device'][did], map['state'][sid]
arrow = map['->']
-print ' '.join([device, arrow, state])
+print(' '.join([device, arrow, state]))
diff --git a/reaktor/commands/taken b/reaktor/commands/taken
index b8beba6..e48fe5e 100755
--- a/reaktor/commands/taken
+++ b/reaktor/commands/taken
@@ -1,13 +1,13 @@
#!/bin/sh
#!/bin/bash
-
+
# domainavailable
# Fast, domain name checker to use from the shell
# Use globs for real fun:
# domainavailable blah{1..3}.{com,net,org,co.uk}
# Inspired by foca / giles:
# http://gilesbowkett.blogspot.com/2009/02/simple-bash-domain-availability.html
-
+
for d in $@;
do
if host "$d" | grep "NXDOMAIN" >&/dev/null; then
diff --git a/reaktor/commands/version b/reaktor/commands/version
index ff3c48f..d9c4c5d 100755
--- a/reaktor/commands/version
+++ b/reaktor/commands/version
@@ -1,21 +1,25 @@
#!/usr/bin/env python
-url="https://pypi.python.org/pypi/Reaktor/json"
-import requests
import reaktor
+import requests
+
+url = "https://pypi.python.org/pypi/Reaktor/json"
+
cur_version = reaktor.__version__
ret = requests.get(url).json()
latest_version = ret["info"]["version"]
+
def vt(v):
return tuple(map(int, (v.split("."))))
+
try:
rel = ret["releases"][cur_version][0]["upload_time"]
-except:
+except Exception:
rel = "unknown release date"
-print("{} - {}".format(cur_version,rel))
+print("{} - {}".format(cur_version, rel))
if vt(latest_version) > vt(cur_version):
print(" newer release available: {}".format(latest_version))
elif vt(latest_version) < vt(cur_version):
@@ -23,5 +27,3 @@ elif vt(latest_version) < vt(cur_version):
else:
# on the most current release
pass
-
-
diff --git a/reaktor/config.py b/reaktor/config.py
index 7f4837c..f5e8e06 100644
--- a/reaktor/config.py
+++ b/reaktor/config.py
@@ -1,26 +1,31 @@
import os
-from os.path import abspath, expanduser,dirname,join
-import reaktor # to get the path to the reaktor basedir
import re
+from os.path import abspath, dirname, expanduser, join
+
+import reaktor # to get the path to the reaktor basedir
+
env = os.environ
# TODO: put this somewhere else
+
+
def str2bool(v):
- return v.lower() in ("yes", "true", "t", "1")
+ return v.lower() in ("yes", "true", "t", "1")
-#### ENVIRON CONFIG
+
+# ENVIRON CONFIG
# this provides a simple means of reconfiguring this config without the need to
# copy-paste the whole thing
-debug = str2bool(env.get('REAKTOR_DEBUG',"False"))
+debug = str2bool(env.get('REAKTOR_DEBUG', "False"))
# IRC_NICKNAME is set if the nick changes and the config is getting reloaded
-name = env.get('REAKTOR_NICKNAME','crabmanner')
-irc_server = env.get('REAKTOR_HOST','irc.freenode.org')
-irc_port = int(env.get('REAKTOR_PORT',6667))
+name = env.get('REAKTOR_NICKNAME', 'crabmanner')
+irc_server = env.get('REAKTOR_HOST', 'irc.freenode.org')
+irc_port = int(env.get('REAKTOR_PORT', 6667))
# TODO: do not implement functionality in the config :\
-workdir = env.get('REAKTOR_STATEDIR',expanduser('~') + '/state')
-irc_channels = env.get('REAKTOR_CHANNELS','#krebs').split(',')
+workdir = env.get('REAKTOR_STATEDIR', expanduser('~') + '/state')
+irc_channels = env.get('REAKTOR_CHANNELS', '#krebs').split(',')
-#### static config
+# static config
# if you want to change this part you have to copy the config
irc_alarm_timeout = 300
irc_hammer_interval = 10
@@ -28,20 +33,21 @@ irc_kill_timeout = 360
irc_nickname = name
irc_restart_timeout = 5
-#### IMPLEMENTATION
+# IMPLEMENTATION
# this config contains the implementation of how commands should match
# TODO: YAY more functionality in config.py ..
# create the workdir somewhere # else in the code ...
# if this fails the bot will fail (which is ok)
-if not os.path.isdir(workdir): os.makedirs(workdir)
+if not os.path.isdir(workdir):
+ os.makedirs(workdir)
-admin_file=workdir+'/admin.lst'
-auth_file=workdir+'/auth.lst'
+admin_file = workdir+'/admin.lst'
+auth_file = workdir+'/auth.lst'
config_filename = abspath(__file__)
-mod_dir=dirname(abspath(reaktor.__file__))
+mod_dir = dirname(abspath(reaktor.__file__))
# the commands dirname (
dist_dir = abspath(join(mod_dir))
@@ -50,89 +56,98 @@ dist_dir = abspath(join(mod_dir))
# TODO: name may change after reconnect, then this pattern fails to match
# this may need a complete refactor of how to create patterns and matches
-## IMPLEMENTATION
-
+# IMPLEMENTATION
me = '\\b' + re.escape(name) + '\\b'
me_or_us = '(?:' + me + '|\\*)'
-indirect_pattern='^'+me_or_us+':\\s*{}\\s*(?:\\s+(?P<args>.*))?$'
+indirect_pattern = '^'+me_or_us+':\\s*{}\\s*(?:\\s+(?P<args>.*))?$'
+
def distc(cmd):
- """ builds a path to a cmd in the command folder of the Reaktor distribution"""
- return join(dist_dir,"commands",cmd)
+ """
+ builds a path to a cmd in the command folder of the Reaktor distribution
+ """
+ return join(dist_dir, "commands", cmd)
def default_command(cap, cmd=None, env=None):
- """ (botname|*): cmd args
-
- query the bot in the channel, e.g.:
- crabmanner: hello
- *: hello
- """
- if not env: env = {}
- if cmd == None: cmd=cap
- return {
- 'capname': cap,
- 'pattern': indirect_pattern.format(cap),
- 'argv': [ distc(cmd) ],
- 'env': env
- }
-
-direct_pattern='^{}\\s*(?:\\s+(?P<args>.*))?$'
+ """ (botname|*): cmd args
+
+ query the bot in the channel, e.g.:
+ crabmanner: hello
+ *: hello
+ """
+ if not env:
+ env = {}
+ if cmd is None:
+ cmd = cap
+ return {
+ 'capname': cap,
+ 'pattern': indirect_pattern.format(cap),
+ 'argv': [distc(cmd)],
+ 'env': env
+ }
+
+
+direct_pattern = '^{}\\s*(?:\\s+(?P<args>.*))?$'
+
+
def simple_command(cap, cmd=None, env=None):
- """ cmd args
-
- query the bot directly, e.g.: /msg crabmanner identity dick butt
- """
- if not env: env = {}
- if cmd == None: cmd=cap
- return {
- 'capname': cap,
- 'pattern': direct_pattern.format(cap),
- 'argv' : [ distc( cmd ) ],
- 'env': env
- }
+ """ cmd args
+
+ query the bot directly, e.g.: /msg crabmanner identity dick butt
+ """
+ if not env:
+ env = {}
+ if cmd is None:
+ cmd = cap
+ return {
+ 'capname': cap,
+ 'pattern': direct_pattern.format(cap),
+ 'argv': [distc(cmd)],
+ 'env': env
+ }
+
# unauthenticated commands
public_commands = [
- default_command('caps', env={
- 'config_filename': config_filename
- }),
- default_command('hello'),
- default_command('badcommand'),
- #default_command('rev'), # TODO: when uploaded to pypi the rev gets lost
- default_command('version'),
- default_command('uptime'),
- default_command('nocommand'),
- default_command('tell', cmd='tell-on_privmsg', env={
- 'state_file': workdir + '/tell.txt'
- }),
- simple_command('identify', env={
- 'config_filename': config_filename
- }),
- # command not found
- #{ 'pattern': '^' + me_or_us + ':.*',
- # 'argv': [ distc('respond'),'You are made of stupid!'] },
- # "highlight"
- { 'pattern': '.*' + me + '.*',
- 'argv': [ distc('say'), 'I\'m famous' ] },
- # identify via direct connect
+ default_command('caps', env={
+ 'config_filename': config_filename
+ }),
+ default_command('hello'),
+ default_command('badcommand'),
+ # default_command('rev'), # TODO: when uploaded to pypi the rev gets lost
+ default_command('version'),
+ default_command('uptime'),
+ default_command('nocommand'),
+ default_command('tell', cmd='tell-on_privmsg', env={
+ 'state_file': workdir + '/tell.txt'
+ }),
+ simple_command('identify', env={
+ 'config_filename': config_filename
+ }),
+ # command not found
+ # { 'pattern': '^' + me_or_us + ':.*',
+ # 'argv': [ distc('respond'),'You are made of stupid!'] },
+ # "highlight"
+ {'pattern': '.*' + me + '.*',
+ 'argv': [distc('say'), 'I\'m famous']},
+ # identify via direct connect
]
# authenticated commands
commands = [
- default_command('reload'),
+ default_command('reload'),
]
on_join = [
- {
- 'capname': 'tell',
- 'argv': [ distc('tell-on_join') ],
- 'env': { 'state_file': workdir + '/tell.txt' }
- }
+ {
+ 'capname': 'tell',
+ 'argv': [distc('tell-on_join')],
+ 'env': {'state_file': workdir + '/tell.txt'}
+ }
]
# Timer
-on_ping = [
-]
+on_ping = []
-## END IMPLEMENTATION
+# END IMPLEMENTATION
diff --git a/reaktor/core.py b/reaktor/core.py
index 18fb074..7a2272c 100755
--- a/reaktor/core.py
+++ b/reaktor/core.py
@@ -10,169 +10,165 @@
"""
+import logging
+import logging.handlers
import os
-from reaktor.ircasy import asybot
from asyncore import loop
+from os.path import dirname
+from re import match
+
import reaktor
+from reaktor.getconf import make_getconf
+from reaktor.ircasy import asybot
from reaktor.translate_colors import translate_colors
-import shlex
-from re import split, search, match
-from os.path import dirname
default_config = dirname(reaktor.__file__)+'/config.py'
-from reaktor.getconf import make_getconf
-import logging,logging.handlers
log = logging.getLogger('Reaktor')
-#hdlr = logging.handlers.SysLogHandler(address='/dev/log', facility=logging.handlers.SysLogHandler.LOG_DAEMON)
-#formatter = logging.Formatter( '%(filename)s: %(levelname)s: %(message)s')
-#hdlr.setFormatter(formatter)
-#log.addHandler(hdlr)
-
-
class Reaktor(asybot):
- def __init__(self,config=default_config,getconf=None):
- self.config = config
-
- if not getconf:
- self.getconf = make_getconf(self.conf)
- else:
- self.getconf = getconf
- log.info("using config file %s"%(config))
-
- asybot.__init__(self,
- getconf('irc_server'),
- getconf('irc_port'),
- getconf('irc_nickname'),
- getconf('irc_channels'),
- hammer_interval=getconf('irc_hammer_interval'),
- alarm_timeout=getconf('irc_alarm_timeout'),
- kill_timeout=getconf('irc_kill_timeout'))
-
- def is_admin(self,prefix):
- try:
- with open(self.getconf('auth_file')) as f:
- for line in f:
- if line.strip() == prefix:
- return True
- except Exception as e:
- log.info(e)
- return False
-
- def on_join(self, prefix, command, params, rest):
- for command in self.getconf('on_join', []):
- self.execute_command(command, None, prefix, params)
-
- def on_ping(self, prefix, command, params, rest):
- for command in self.getconf('on_ping', []):
- prefix = '!' # => env = { _prefix: '!', _from: '' }
- params = command.get('targets') # TODO why don't we get a list here and use ','.join() ?
- self.execute_command(command, None, prefix, params)
-
- def on_privmsg(self, prefix, command, params, rest):
- if not ( self.nickname == self.getconf('name')):
- # reload config if the name changed
- # TODO: this sucks, use another sidechannel to tell config the new
- # nickname
- log.debug("nickname differs ('{}' to '{}')".format(
- self.nickname, self.getconf('name')))
-
- os.environ['REAKTOR_NICKNAME'] = self.nickname
- self.getconf = make_getconf(self.config)
- log.info('nickname changed to {}'.format(self.getconf('name')))
-
- for command in self.getconf('commands'):
- y = match(command['pattern'], rest)
- if y:
- if not self.is_admin(prefix):
- self.PRIVMSG(params,'unauthorized!')
+ def __init__(self, config=default_config, getconf=None):
+ self.config = config
+
+ if not getconf:
+ self.getconf = make_getconf(self.conf)
else:
- return self.execute_command(command, y, prefix, params)
-
- for command in self.getconf('public_commands'):
- y = match(command['pattern'], rest)
- if y:
- return self.execute_command(command, y, prefix, params)
-
-
- def execute_command(self, command, match, prefix, target):
- from os.path import realpath, dirname, join
- from subprocess import Popen as popen, PIPE
- from time import time
-
- #TODO: allow only commands below ./commands/
- exe = join(dirname(realpath(dirname(__file__))), command['argv'][0])
- myargv = [exe] + command['argv'][1:]
- try:
- if match and match.groupdict().get('args', None):
- myargv += [match.groupdict()['args']]
- except:
- log.info("cannot parse args!")
-
- cwd = self.getconf('workdir')
- if not os.access(cwd,os.W_OK):
- log.error("Workdir '%s' is not Writable! Falling back to root dir"%cwd)
- cwd = "/"
-
- env = {}
-
- env.update(os.environ) # first merge os.environ
- env.update(command.get('env', {})) # then env of cfg
-
- env['_prefix'] = prefix
- env['_from'] = prefix.split('!', 1)[0]
-
- log.debug('self:' +self.nickname)
- # when receiving /query, answer to the user, not to self
- if self.nickname in target:
- target.remove(self.nickname)
- target.append(env['_from'])
- log.debug('target:' +str(target))
-
- start = time()
- try:
- log.debug("Running : %s"%str(myargv))
- log.debug("Environ : %s"%(str(env)))
- p = popen(myargv, bufsize=1, stdout=PIPE, stderr=PIPE, env=env, cwd=cwd)
- except Exception as error:
- self.ME(target, 'brain damaged')
- log.error('OSError@%s: %s' % (myargv, error))
- return
- pid = p.pid
- for line in iter(p.stdout.readline, ''.encode()):
- try:
- self.PRIVMSG(target, translate_colors(line.decode()))
- 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:
- self.ME(target, 'mimimi')
+ self.getconf = getconf
+ log.info("using config file %s" % (config))
+
+ asybot.__init__(self,
+ getconf('irc_server'),
+ getconf('irc_port'),
+ getconf('irc_nickname'),
+ getconf('irc_channels'),
+ hammer_interval=getconf('irc_hammer_interval'),
+ alarm_timeout=getconf('irc_alarm_timeout'),
+ kill_timeout=getconf('irc_kill_timeout'))
+
+ def is_admin(self, prefix):
+ try:
+ with open(self.getconf('auth_file')) as f:
+ for line in f:
+ if line.strip() == prefix:
+ return True
+ except Exception as e:
+ log.info(e)
+ return False
+
+ def on_join(self, prefix, command, params, rest):
+ for command in self.getconf('on_join', []):
+ self.execute_command(command, None, prefix, params)
+
+ def on_ping(self, prefix, command, params, rest):
+ for command in self.getconf('on_ping', []):
+ prefix = '!' # => env = { _prefix: '!', _from: '' }
+ # TODO why don't we get a list here and use ','.join() ?
+ params = command.get('targets')
+ self.execute_command(command, None, prefix, params)
+
+ def on_privmsg(self, prefix, command, params, rest):
+ if not (self.nickname == self.getconf('name')):
+ # reload config if the name changed
+ # TODO: this sucks, use another sidechannel to tell config the
+ # new nickname
+ log.debug("nickname differs ('{}' to '{}')".format(
+ self.nickname, self.getconf('name')))
+
+ os.environ['REAKTOR_NICKNAME'] = self.nickname
+ self.getconf = make_getconf(self.config)
+ log.info('nickname changed to {}'.format(self.getconf('name')))
+
+ for command in self.getconf('commands'):
+ y = match(command['pattern'], rest)
+ if y:
+ if not self.is_admin(prefix):
+ self.PRIVMSG(params, 'unauthorized!')
+ else:
+ return self.execute_command(command, y, prefix, params)
+
+ for command in self.getconf('public_commands'):
+ y = match(command['pattern'], rest)
+ if y:
+ return self.execute_command(command, y, prefix, params)
+
+ def execute_command(self, command, match, prefix, target):
+ from os.path import realpath, dirname, join
+ from subprocess import Popen as popen, PIPE
+ from time import time
+
+ # TODO: allow only commands below ./commands/
+ exe = join(dirname(realpath(dirname(__file__))), command['argv'][0])
+ myargv = [exe] + command['argv'][1:]
+ try:
+ if match and match.groupdict().get('args', None):
+ myargv += [match.groupdict()['args']]
+ except Exception as e:
+ log.info("cannot parse args!: {}".format(e))
+
+ cwd = self.getconf('workdir')
+ if not os.access(cwd, os.W_OK):
+ log.error(
+ "Workdir '%s' is not Writable! Falling back to root dir" % cwd)
+ cwd = "/"
+
+ env = {}
+
+ env.update(os.environ) # first merge os.environ
+ env.update(command.get('env', {})) # then env of cfg
+
+ env['_prefix'] = prefix
+ env['_from'] = prefix.split('!', 1)[0]
+
+ log.debug('self:' + self.nickname)
+ # when receiving /query, answer to the user, not to self
+ if self.nickname in target:
+ target.remove(self.nickname)
+ target.append(env['_from'])
+ log.debug('target:' + str(target))
+
+ start = time()
+ try:
+ log.debug("Running : %s" % str(myargv))
+ log.debug("Environ : %s" % (str(env)))
+ p = popen(myargv, bufsize=1, stdout=PIPE,
+ stderr=PIPE, env=env, cwd=cwd)
+ except Exception as error:
+ self.ME(target, 'brain damaged')
+ log.error('OSError@%s: %s' % (myargv, error))
+ return
+ pid = p.pid
+ for line in iter(p.stdout.readline, ''.encode()):
+ try:
+ self.PRIVMSG(target, translate_colors(line.decode()))
+ 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:
+ self.ME(target, 'mimimi')
+
def main():
- import sys
- from docopt import docopt
- from docopt import docopt
- args = docopt(__doc__)
- conf = args['CONFIG'] if args['CONFIG'] else default_config
- getconf = make_getconf(conf)
- logging.basicConfig(level = logging.DEBUG if getconf('debug') else
- logging.INFO)
- log.debug("Debug enabled")
-
- if args['run']:
- Reaktor(conf,getconf)
- loop()
- elif args['get-config']:
- print(open(conf).read())
+ from docopt import docopt
+ args = docopt(__doc__)
+ conf = args['CONFIG'] if args['CONFIG'] else default_config
+ getconf = make_getconf(conf)
+ logging.basicConfig(level=logging.DEBUG if getconf('debug') else
+ logging.INFO)
+ log.debug("Debug enabled")
+
+ if args['run']:
+ Reaktor(conf, getconf)
+ loop()
+ elif args['get-config']:
+ print(open(conf).read())
+
if __name__ == "__main__":
main()
-
diff --git a/reaktor/getconf.py b/reaktor/getconf.py
index e513e31..cfb38f5 100644
--- a/reaktor/getconf.py
+++ b/reaktor/getconf.py
@@ -1,6 +1,6 @@
-#getconf = make_getconf("dateiname.json")
-#getconf(key) -> value
-#oder error
+# getconf = make_getconf("dateiname.json")
+# getconf(key) -> value
+# oder error
import imp
import os
@@ -9,9 +9,8 @@ import os
def make_getconf(filename):
def getconf(prop, default_value=None):
prop_split = prop.split('.')
- string = ''
config = load_config(filename)
- #imp.reload(config)
+ # imp.reload(config)
tmp = config.__dict__
for pr in prop_split:
if pr in tmp:
@@ -26,9 +25,10 @@ def make_getconf(filename):
def load_config(filename):
dirname = os.path.dirname(filename)
modname, ext = os.path.splitext(os.path.basename(filename))
- file, pathname, description = imp.find_module(modname, [ dirname ])
+ file, pathname, description = imp.find_module(modname, [dirname])
try:
ret = imp.load_module(modname, file, pathname, description)
finally:
- if file: file.close()
+ if file:
+ file.close()
return ret
diff --git a/reaktor/ircasy.py b/reaktor/ircasy.py
index 312f074..f8f85d6 100644
--- a/reaktor/ircasy.py
+++ b/reaktor/ircasy.py
@@ -2,198 +2,206 @@
#
# //Reaktor/IRC/asybot.py
#
+import logging
+import logging.handlers
from asynchat import async_chat as asychat
-from asyncore import loop
-from socket import AF_INET, SOCK_STREAM,gethostname
-from signal import SIGALRM, signal, alarm
-from datetime import datetime as date, timedelta
-from time import sleep
-from sys import exit
-from re import split, search, match
+from datetime import datetime as date
+from datetime import timedelta
+from re import search, split
+from signal import SIGALRM, alarm, signal
+from socket import AF_INET, SOCK_STREAM
from textwrap import TextWrapper
-
-import logging,logging.handlers
+from time import sleep
# 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, channels, realname=False, username=False, hostname=False, hammer_interval=10, alarm_timeout=300, kill_timeout=360, loglevel=logging.ERROR):
- asychat.__init__(self)
- #logger magic
- self.log = logging.getLogger('asybot_' + nickname)
- self.nickname = nickname
-
- if realname:
- self.realname = realname
- else:
- self.realname = nickname
-
- if username:
- self.username = username
- else:
- self.username = nickname
-
- if hostname:
- self.hostname = hostname
- else:
- self.hostname = nickname
-
- self.retry = True
- self.server = server
- self.port = port
- self.channels = channels
- self.data = ''
- self.myterminator = '\r\n'
- self.set_terminator(self.myterminator.encode())
- self.create_socket(AF_INET, SOCK_STREAM)
- self.connect((self.server, self.port))
- self.wrapper = TextWrapper(subsequent_indent=" ",width=400)
-
- self.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 = alarm_timeout
- self.hammer_interval = hammer_interval
- self.kill_timeout = kill_timeout
- try:
- signal(SIGALRM, lambda signum, frame: self.alarm_handler())
- except Exception as e:
- print('asybot: ' + str(e))
- self.reset_alarm()
-
- def reset_alarm(self):
- self.last_activity = date.now()
- alarm(self.alarm_timeout)
-
- def alarm_handler(self):
- delta = date.now() - self.last_activity
- if delta > timedelta(seconds=self.kill_timeout):
- self.log.error('No data for %s. Giving up...' % delta)
- self.handle_disconnect()
- else:
- self.log.error('No data for %s. PINGing server...' % delta)
- self.push('PING :%s' % self.nickname)
- alarm(self.hammer_interval)
-
- def collect_incoming_data(self, data):
- try:
- self.data += data.decode()
- except Exception as e:
- print('error decoding message: ' + str(e));
- print('current data: %s' % self.data);
- print('received data: %s' % data);
- print('trying to decode as latin1')
- self.data += data.decode('latin1')
-
- def found_terminator(self):
- self.log.debug('<< %s' % self.data)
-
- message = self.data
- self.data = ''
- try:
- _, prefix, command, params, rest, _ = \
- split('^(?::(\S+)\s)?(\S+)((?:\s[^:]\S*)*)(?:\s:(.*))?$', message)
- except Exception as e:
- print("cannot split message :(\nmsg: %s"%message)
- return
- params = params.split(' ')[1:]
-
- if command == 'PING':
- self.push('PONG :%s' % rest)
- self.log.debug("Replying to servers PING with PONG :%s" %rest)
- self.on_ping(prefix, command, params, rest)
-
- elif command == 'PRIVMSG':
- self.on_privmsg(prefix, command, params, rest)
-
- elif command == 'INVITE':
- self.on_invite(prefix, command, params, rest)
-
- elif command == 'KICK':
- self.on_kick(prefix, command, params, rest)
-
- elif command == 'JOIN':
- self.on_join(prefix, command, params, rest)
-
- elif command == '433':
- # ERR_NICKNAMEINUSE, retry with another name
- self.on_nickinuse(prefix, command, params, rest)
-
- elif command == '376' or '422':
- self.on_welcome(prefix, command, params, rest)
-
- self.reset_alarm()
-
- def push(self, message):
- try:
- self.log.debug('>> %s' % message)
- msg = (message + self.myterminator).encode()
- self.log.debug('>> %s' % msg)
- asychat.push(self, msg)
- except:
+ def __init__(
+ self, server, port, nickname, channels, realname=False, username=False,
+ hostname=False, hammer_interval=10, alarm_timeout=300,
+ kill_timeout=360, loglevel=logging.ERROR
+ ):
+ asychat.__init__(self)
+ # logger magic
+ self.log = logging.getLogger('asybot_' + nickname)
+ self.nickname = nickname
+
+ if realname:
+ self.realname = realname
+ else:
+ self.realname = nickname
+
+ if username:
+ self.username = username
+ else:
+ self.username = nickname
+
+ if hostname:
+ self.hostname = hostname
+ else:
+ self.hostname = nickname
+
+ self.retry = True
+ self.server = server
+ self.port = port
+ self.channels = channels
+ self.data = ''
+ self.myterminator = '\r\n'
+ self.set_terminator(self.myterminator.encode())
+ self.create_socket(AF_INET, SOCK_STREAM)
+ self.connect((self.server, self.port))
+ self.wrapper = TextWrapper(subsequent_indent=" ", width=400)
+
+ self.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 = alarm_timeout
+ self.hammer_interval = hammer_interval
+ self.kill_timeout = kill_timeout
+ try:
+ signal(SIGALRM, lambda signum, frame: self.alarm_handler())
+ except Exception as e:
+ print('asybot: ' + str(e))
+ self.reset_alarm()
+
+ def reset_alarm(self):
+ self.last_activity = date.now()
+ alarm(self.alarm_timeout)
+
+ def alarm_handler(self):
+ delta = date.now() - self.last_activity
+ if delta > timedelta(seconds=self.kill_timeout):
+ self.log.error('No data for %s. Giving up...' % delta)
+ self.handle_disconnect()
+ else:
+ self.log.error('No data for %s. PINGing server...' % delta)
+ self.push('PING :%s' % self.nickname)
+ alarm(self.hammer_interval)
+
+ def collect_incoming_data(self, data):
+ try:
+ self.data += data.decode()
+ except Excepti