Compare commits

..

23 Commits

Author SHA1 Message Date
braph
98e9efe682 re-inserted mutex code 2016-09-06 18:25:05 +02:00
braph
abb6494acf xchoose: added further error handling 2016-09-06 13:23:46 +02:00
braph
8ab4e8cdd4 added xchoose command 2016-09-05 23:53:30 +02:00
Thorsten
d92a177aa8 mutex for events, re-enable dsa-watcher 2016-09-05 23:39:34 +02:00
Thorsten
bddc3034d5 put a show on the pancake on its head 2016-09-05 20:30:15 +02:00
Thorsten
3b506d737c put a pancake on its head 2016-09-05 20:07:47 +02:00
Thorsten S
f00555de90 put a pancake on its head 2016-08-21 15:53:27 +02:00
Thorsten S
c3f5371fe3 put a pancake on its head 2016-08-21 15:39:43 +02:00
Thorsten
e0385a7db3 second iteration of morse code plugin, provided by braph 2016-08-13 02:32:08 +02:00
Thorsten
cde081dad2 who let the bots out? 2016-08-13 02:31:45 +02:00
Thorsten
492ca7a7c8 spellcheck 2016-07-18 20:16:40 +02:00
Thorsten
877de9b5c3 fix punctuation 2016-07-08 21:19:07 +02:00
Thorsten
f8373a61c4 decisive bot 2016-07-08 21:17:08 +02:00
Thorsten
d9d87f114a Merge remote-tracking branch 'origin/master' 2016-06-22 22:40:31 +02:00
Thorsten
4541dd0ebb systemd support and separate message queues per room 2016-06-22 22:40:22 +02:00
Thorsten
efd18525bb systemd support and separate message queues per room 2016-06-22 22:13:51 +02:00
Thorsten
dff83acaf6 fix bug 2016-06-12 21:02:37 +02:00
Thorsten
94c78335fb add doc 2016-05-27 21:56:10 +02:00
Thorsten
d5886fbd94 fix 2016-05-27 21:48:33 +02:00
Thorsten
f7ab2cfbdd add multi-choice mod by braph 2016-05-27 21:31:31 +02:00
Thorsten
5b9ed2ef94 disable repeater 2016-05-27 20:44:35 +02:00
Thorsten
5ffa3f0dc7 disable bot recognizer 2016-05-27 20:40:26 +02:00
Thorsten
1c0f7a7024 disable add_to_botlist 2016-05-27 20:38:40 +02:00
11 changed files with 501 additions and 34 deletions

View File

@@ -20,6 +20,7 @@
vars: vars:
- botrepo: http://aero2k.de/t/repos/urlbot-native.git - botrepo: http://aero2k.de/t/repos/urlbot-native.git
- pypi_mirror: http://pypi.fcio.net/simple/ - pypi_mirror: http://pypi.fcio.net/simple/
- systemd: true
tasks: tasks:
- include_vars: credentials.yml - include_vars: credentials.yml
tags: [render_config] tags: [render_config]
@@ -27,6 +28,7 @@
shell: virtualenv -p python3 --system-site-packages ~/botenv creates=~/botenv/bin/activate shell: virtualenv -p python3 --system-site-packages ~/botenv creates=~/botenv/bin/activate
- name: virtualenv for supervisord - name: virtualenv for supervisord
shell: virtualenv -p python2 ~/svenv creates=~/svenv/bin/activate shell: virtualenv -p python2 ~/svenv creates=~/svenv/bin/activate
when: not systemd
- name: clone repository - name: clone repository
git: repo="{{botrepo}}" dest=~/urlbot force=yes update=yes git: repo="{{botrepo}}" dest=~/urlbot force=yes update=yes
register: source_code register: source_code
@@ -34,6 +36,7 @@
pip: requirements="~/urlbot/requirements.txt" virtualenv=~/botenv extra_args="-i {{pypi_mirror}}" pip: requirements="~/urlbot/requirements.txt" virtualenv=~/botenv extra_args="-i {{pypi_mirror}}"
- name: install supervisor - name: install supervisor
pip: name=supervisor virtualenv=~/svenv extra_args="-i {{pypi_mirror}}" pip: name=supervisor virtualenv=~/svenv extra_args="-i {{pypi_mirror}}"
when: not systemd
- name: set configuration - name: set configuration
lineinfile: dest=~/urlbot/local_config.ini create=yes line="{{item.key}} = {{item.value}}" regexp="^{{item.key}}.=" lineinfile: dest=~/urlbot/local_config.ini create=yes line="{{item.key}} = {{item.value}}" regexp="^{{item.key}}.="
@@ -60,29 +63,94 @@
- name: create supervisor config - name: create supervisor config
copy: src=supervisord.conf dest=~/supervisord.conf copy: src=supervisord.conf dest=~/supervisord.conf
register: supervisord register: supervisord
when: not systemd
- name: create directory for systemd unit file
shell: mkdir -p ~/.config/systemd/user/ creates=~/.config/systemd/user/
when: systemd
- name: create unitfile
copy: src=urlbug@.service dest=~/.config/systemd/user/urlbug@.service
when: systemd
register: unitfile
# crapshit does not work
- name: reload unitfiles
become: true
shell: systemctl daemon-reload
when: unitfile.changed
ignore_errors: true
- name: enable services
shell: "systemctl --user enable urlbug@{{item}}.service"
with_items:
- idlebot
- urlbot
when: systemd
- name: verify supervisor running - name: verify supervisor running
shell: nc -z 127.0.0.1 9004; echo $? executable=/bin/bash shell: nc -z 127.0.0.1 9004; echo $? executable=/bin/bash
register: supervisor_running register: supervisor_running
changed_when: false changed_when: false
when: not systemd
- name: start supervisord - name: start supervisord
shell: source ~/svenv/bin/activate && supervisord executable=/bin/bash shell: source ~/svenv/bin/activate && supervisord executable=/bin/bash
register: start_supervisor register: start_supervisor
when: supervisord.changed or supervisor_running.stdout == "1" when:
- not systemd
- supervisord.changed or supervisor_running.stdout == "1"
#changed_when: "'already listening' not in start_supervisor.stdout" #changed_when: "'already listening' not in start_supervisor.stdout"
- name: activate supervisord changes - name: activate supervisord changes
when: supervisord.changed
shell: source ~/svenv/bin/activate && supervisorctl reload executable=/bin/bash shell: source ~/svenv/bin/activate && supervisorctl reload executable=/bin/bash
when:
- not systemd
- supervisord.changed
- name: idlebot started - name: idlebot started
supervisorctl: name=idlebot state=restarted supervisorctl_path=~/svenv/bin/supervisorctl supervisorctl: name=idlebot state=restarted supervisorctl_path=~/svenv/bin/supervisorctl
when: (source_code.changed or urlbot_config.changed) and not supervisord.changed when:
- not systemd
- (source_code.changed or urlbot_config.changed) and not supervisord.changed
- pause: seconds=30 # following tasks are workaround for missing ansible systemd-user support
when: (source_code.changed or urlbot_config.changed) and not supervisord.changed - name: get systemd unit status
shell: systemctl --user status urlbug.slice
register: systemd_unit_status
- debug: var=systemd_unit_status
- debug: msg="{{'{{item}}.service' not in systemd_unit_status.stdout}}"
with_items:
- idlebot
- urlbot
- name: bots started
shell: "systemctl --user start urlbug@{{item}}.service && sleep 20"
with_items:
- idlebot
- urlbot
when: systemd and '{{item}}.service' not in systemd_unit_status.stdout
register: started_bots
- debug: var=started_bots
- name: bots restarted
shell: "systemctl --user restart urlbug@{{item}}.service && sleep 10"
with_items:
- idlebot
- urlbot
when:
- systemd
- source_code.changed or urlbot_config.changed
- pause: seconds=20
when:
- not systemd
- (source_code.changed or urlbot_config.changed) and not supervisord.changed
- name: urlbot started - name: urlbot started
supervisorctl: name=bot state=restarted supervisorctl_path=~/svenv/bin/supervisorctl supervisorctl: name=bot state=restarted supervisorctl_path=~/svenv/bin/supervisorctl
when: (source_code.changed or urlbot_config.changed) and not supervisord.changed when:
- not systemd
- (source_code.changed or urlbot_config.changed) and not supervisord.changed

View File

@@ -0,0 +1,2 @@
ansible
markupsafe

12
deploy/urlbug@.service Normal file
View File

@@ -0,0 +1,12 @@
[Unit]
Description=jabber bot entertaining and supporting activity on jabber MUCs
[Service]
ExecStart=/home/jabberbot/botenv/bin/python3 /home/jabberbot/urlbot/%i.py
WorkingDirectory=/home/jabberbot/urlbot/
StandardOutput=journal+console
StandardError=journal+console
Restart=always
[Install]
WantedBy=multi-user.target

View File

@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging
import time import time
import sched import sched
import threading import threading
@@ -8,7 +9,7 @@ EVENTLOOP_DELAY = 0.100 # seconds
event_list = sched.scheduler(time.time, time.sleep) event_list = sched.scheduler(time.time, time.sleep)
def register_active_event(t, callback, args, action_runner, plugin, msg_obj): def register_active_event(t, callback, args, action_runner, plugin, msg_obj, mutex=None):
""" """
Execute a callback at a given time and react on the output Execute a callback at a given time and react on the output
@@ -24,10 +25,14 @@ def register_active_event(t, callback, args, action_runner, plugin, msg_obj):
action = callback(*func_args) action = callback(*func_args)
if action: if action:
action_runner(action=action, plugin=plugin, msg_obj=msg_obj) action_runner(action=action, plugin=plugin, msg_obj=msg_obj)
event_list.enterabs(t, 0, func, args) register_event(t, func, args, mutex=mutex)
def register_event(t, callback, args): def register_event(t, callback, args, **kwargs):
for pending_event in event_list.queue:
if kwargs.get('mutex') and pending_event.kwargs.get('mutex', None) == kwargs.get('mutex'):
logging.debug("Dropped event: %s", kwargs.get('mutex'))
return
event_list.enterabs(t, 0, callback, args) event_list.enterabs(t, 0, callback, args)

View File

@@ -20,6 +20,7 @@ class IdleBot(ClientXMPP):
self.add_event_handler('session_start', self.session_start) self.add_event_handler('session_start', self.session_start)
self.add_event_handler('groupchat_message', self.muc_message) self.add_event_handler('groupchat_message', self.muc_message)
self.add_event_handler('disconnected', self.disconnected) self.add_event_handler('disconnected', self.disconnected)
self.add_event_handler('presence_error', self.disconnected)
self.priority = 0 self.priority = 0
self.status = None self.status = None
self.show = None self.show = None
@@ -29,7 +30,7 @@ class IdleBot(ClientXMPP):
self.add_event_handler('muc::%s::got_offline' % room, self.muc_offline) self.add_event_handler('muc::%s::got_offline' % room, self.muc_offline)
def disconnected(self, _): def disconnected(self, _):
exit(0) self.disconnect(wait=True)
def session_start(self, _): def session_start(self, _):
self.get_roster() self.get_roster()
@@ -81,8 +82,7 @@ class IdleBot(ClientXMPP):
""" """
disconnect and exit disconnect and exit
""" """
self.disconnect() self.disconnect(wait=True)
sys.exit(1)
def start(botclass, active=False): def start(botclass, active=False):

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging import logging
import re
import events import events
import json import json
import random import random
@@ -15,6 +16,7 @@ import config
from common import VERSION from common import VERSION
from rate_limit import RATE_FUN, RATE_GLOBAL, RATE_INTERACTIVE, RATE_NO_SILENCE, RATE_NO_LIMIT from rate_limit import RATE_FUN, RATE_GLOBAL, RATE_INTERACTIVE, RATE_NO_SILENCE, RATE_NO_LIMIT
from plugin_system import pluginfunction, ptypes, plugin_storage, plugin_enabled_get, plugin_enabled_set from plugin_system import pluginfunction, ptypes, plugin_storage, plugin_enabled_get, plugin_enabled_set
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@@ -92,7 +94,6 @@ def command_plugin_activation(argv, **args):
@pluginfunction('list', 'list plugin and parser status', ptypes.COMMAND) @pluginfunction('list', 'list plugin and parser status', ptypes.COMMAND)
def command_list(argv, **args): def command_list(argv, **args):
log.info('list plugin called') log.info('list plugin called')
if 'enabled' in argv and 'disabled' in argv: if 'enabled' in argv and 'disabled' in argv:
@@ -279,20 +280,189 @@ def command_dice(argv, **args):
} }
@pluginfunction('xchoose', 'chooses randomly between nested option groups', ptypes.COMMAND, ratelimit_class=RATE_INTERACTIVE)
def command_xchoose(argv, **args):
class ChooseTree():
def __init__(self, item=None):
self.item = item
self.tree = None
self.closed = False
# opening our root node
if self.item is None:
self.open()
def open(self):
if self.tree is None:
self.tree = []
elif self.closed:
raise Exception("cannot re-open group for item '%s'" % (self.item))
def close(self):
if self.tree is None:
raise Exception("close on unopened bracket")
elif len(self.tree) == 0:
raise Exception("item '%s' has a group without sub options" % (self.item))
else:
self.closed = True
def last(self):
return self.tree[-1]
def choose(self):
if self.item:
yield self.item
if self.tree:
sel = random.choice(self.tree)
for sub in sel.choose():
yield sub
def add(self, item):
self.tree.append( ChooseTree(item) )
# because of error handling we're nesting this function here
def xchoose(line):
item = ''
quote = None
choose_tree = ChooseTree()
choose_stack = [ choose_tree ]
bracket_stack = []
for pos, c in enumerate(line, 1):
try:
if quote:
if c == quote:
quote = None
else:
item += c
elif c == ' ':
if item:
choose_stack[-1].add(item)
item = ''
elif c in ('(', '[', '{', '<'):
if item:
choose_stack[-1].add(item)
item = ''
try:
last = choose_stack[-1].last()
last.open()
choose_stack.append(last)
bracket_stack.append(c)
except IndexError:
raise Exception("cannot open group without preceding option")
elif c in (')', ']', '}', '>'):
if not bracket_stack:
raise Exception("missing leading bracket for '%s'" % (c))
opening_bracket = bracket_stack.pop(-1)
wanted_closing_bracket = { '(':')', '[':']', '{':'}', '<':'>' }[opening_bracket]
if c != wanted_closing_bracket:
raise Exception("bracket mismatch, wanted bracket '%s' but got '%s'" % (
wanted_closing_bracket, c))
if item:
choose_stack[-1].add(item)
item = ''
choose_stack[-1].close()
choose_stack.pop(-1)
elif c in ('"', "'"):
quote = c
else:
item += c
except Exception as e:
raise Exception("%s (at pos %d)" % (e, pos))
if bracket_stack:
raise Exception("missing closing bracket for '%s'" % (bracket_stack[-1]))
if quote:
raise Exception("missing closing quote (%s)" % (quote))
if item:
choose_stack[-1].add(item)
return ' '.join(choose_tree.choose())
# start of command_xchoose
line = re.sub('.*xchoose *', '', args['data'])
if not line:
return {
'msg': '%s: %s' % (args['reply_user'], 'missing options')
}
try:
return {
'msg': '%s: %s' % (args['reply_user'], xchoose(line))
}
except Exception as e:
return {
'msg': '%s: %s' % (args['reply_user'], str(e))
}
@pluginfunction('choose', 'chooses randomly between arguments', ptypes.COMMAND, ratelimit_class=RATE_INTERACTIVE) @pluginfunction('choose', 'chooses randomly between arguments', ptypes.COMMAND, ratelimit_class=RATE_INTERACTIVE)
def command_choose(argv, **args): def command_choose(argv, **args):
alternatives = argv alternatives = argv
binary = (
(('Yes.', 'Yeah!', 'Ok!', 'Aye!', 'Great!'), 4),
(('No.', 'Naah..', 'Meh.', 'Nay.', 'You stupid?'), 4),
(('Maybe.', 'Dunno.', 'I don\'t care.'), 2)
)
def weighted_choice(choices):
total = sum(w for c, w in choices)
r = random.uniform(0, total)
upto = 0
for c, w in choices:
if upto + w >= r:
return c
upto += w
# single or no choice
if len(alternatives) < 2: if len(alternatives) < 2:
return { return {
'msg': '{}: {}.'.format(args['reply_user'], random.choice(['Yes', 'No'])) 'msg': '{}: {}'.format(args['reply_user'], random.choice(weighted_choice(binary)))
} }
elif 'choose' not in alternatives:
choice = random.choice(alternatives) choice = random.choice(alternatives)
log.info('sent random choice')
return { return {
'msg': '%s: I prefer %s!' % (args['reply_user'], choice) 'msg': '%s: I prefer %s!' % (args['reply_user'], choice)
} }
def choose_between(options):
responses = []
current_choices = []
for item in options:
if item == 'choose':
if len(current_choices) < 2:
responses.append(random.choice(weighted_choice(binary)))
else:
responses.append(random.choice(current_choices))
current_choices = []
else:
current_choices.append(item)
if len(current_choices) < 2:
responses.append(random.choice(weighted_choice(binary)))
else:
responses.append(random.choice(current_choices))
return responses
log.info('sent multiple random choices')
return {
'msg': '%s: My choices are: %s!' % (args['reply_user'], ', '.join(choose_between(alternatives)))
}
@pluginfunction('teatimer', 'sets a tea timer to $1 or currently %d seconds' % config.conf_get('tea_steep_time'), @pluginfunction('teatimer', 'sets a tea timer to $1 or currently %d seconds' % config.conf_get('tea_steep_time'),
ptypes.COMMAND) ptypes.COMMAND)
@@ -324,7 +494,8 @@ def command_teatimer(argv, **args):
), ),
'event': { 'event': {
'time': ready, 'time': ready,
'msg': (args['reply_user'] + ': Your tea is ready!') 'msg': (args['reply_user'] + ': Your tea is ready!'),
'mutex': 'teatimer_{}'.format(args['reply_user'])
} }
} }
@@ -590,9 +761,11 @@ def command_dsa_watcher(argv=None, **_):
msg = 'next crawl set to %s' % time.strftime('%Y-%m-%d %H:%M', time.localtime(crawl_at)) msg = 'next crawl set to %s' % time.strftime('%Y-%m-%d %H:%M', time.localtime(crawl_at))
out.append(msg) out.append(msg)
return { return {
# 'msg': out,
'event': { 'event': {
'time': crawl_at, 'time': crawl_at,
'command': (command_dsa_watcher, ([],)) 'command': (command_dsa_watcher, ([],)),
'mutex': 'dsa'
} }
} }
@@ -621,8 +794,9 @@ def remove_from_botlist(argv, **args):
return False return False
@pluginfunction("add-to-botlist", "add a user to the botlist", ptypes.COMMAND) @pluginfunction("add-to-botlist", "add a user to the botlist", ptypes.COMMAND, enabled=False)
def add_to_botlist(argv, **args): def add_to_botlist(argv, **args):
return {'msg': 'feature disabled until channel separation'}
if not argv: if not argv:
return {'msg': "wrong number of arguments!"} return {'msg': "wrong number of arguments!"}
suspect = argv[0] suspect = argv[0]
@@ -776,6 +950,7 @@ def raise_an_error(argv, **args):
@pluginfunction('repeat', 'repeat the last message', ptypes.COMMAND) @pluginfunction('repeat', 'repeat the last message', ptypes.COMMAND)
def repeat_message(argv, **args): def repeat_message(argv, **args):
if args['stack']:
return { return {
'msg': args['stack'][-1]['body'] 'msg': args['stack'][-1]['body']
} }

View File

@@ -17,7 +17,7 @@ comment_joins_strings = [
def comment_joins(**args): def comment_joins(**args):
# max elapsed time between the latest and the N latest join # max elapsed time between the latest and the N latest join
timespan = 120 timespan = 120
max_joins = config.runtime_config_store max_joins = 6
current_timestamp = int(time.time()) current_timestamp = int(time.time())

176
plugins/morse.py Normal file
View File

@@ -0,0 +1,176 @@
# -*- coding: utf-8 -*-
import logging
import re
from plugin_system import pluginfunction, ptypes
from rate_limit import RATE_FUN, RATE_GLOBAL
log = logging.getLogger(__name__)
# copy from https://de.wikipedia.org/wiki/Morsezeichen
raw_wiki_copy = """
B · · ·
C · ·
D · ·
F· · ·
G ·
H· · · ·
I· ·
K ·
· ·
M
N ·
O
·
Q ·
·
S· · ·
T
U· ·
V· · ·
X · ·
Y ·
Z · ·
2· ·
3· · ·
4· · · ·
5· · · · ·
6 · · · ·
7 · · ·
8 · ·
9 ·
0
"""
# machen dictionary aus wikipaste
def wiki_paste_to_morse_dict(wikicopy):
wikicopy = wikicopy.replace(' ', '')
morse_dict = {l[0]: l[1:] for l in wikicopy.splitlines() if l}
return morse_dict
ascii_morse = wiki_paste_to_morse_dict(raw_wiki_copy)
morse_ascii = {v: k for k, v in ascii_morse.items()}
# return a dictionary of possible morse-chars as key
# and their count as value
def possible_morse_chars(string):
"""
returns dit,dah or None
"""
stats = {}
for c in re.sub("[\w\d ]", '', string):
try:
stats[c] += 1
except KeyError:
stats[c] = 1
return stats
# return morse-encoded string
def morse_encode(string, dot='·', dash='', sep=' ', ignore_unknown=False):
morse_codes = []
for char in string.upper():
try:
morse_codes.append(ascii_morse[char].replace('·', dot).replace('', dash))
except KeyError:
if not ignore_unknown:
morse_codes.append(char)
return sep.join(morse_codes)
# return morse-decoded string with number of errors as tuple
# -> (decoded string, num errors)
def morse_decode(string, dot=None, dash=None):
"""
decode a "morse string" to ascii text
uses \s{2,} as word separator
"""
# dot and dash given, just decode
if dot and dash:
errors = 0
words = []
# drawback: does not allow single characters.
for match in re.finditer('([{dit}{dah}]+((?:\\s)[{dit}{dah}]+)+|\w+)'.format(dit=dot, dah=dash), string):
word = match.group()
log.debug("morse word: ", word)
if any([dot in word, dash in word]):
w = []
for morse_character in word.split():
try:
character = morse_ascii[morse_character.replace(dot, '·').replace(dash, '')]
print("Converted \t{} \tto {}".format(morse_character, character))
except KeyError:
character = morse_character
errors += 1
w.append(character)
words.append(''.join(w))
# words.append(''.join([morse_ascii[x.replace(dot, '·').replace(dash, '')] for x in word.split()]))
else:
words.append(word)
return ' '.join(words), errors
# dot/dash given, search for dash/dot
else:
if not dash:
dash_stats = {x: string.count(x) for x in '-_'}
dash = max(dash_stats, key=dash_stats.get)
if not dot:
dot_stats = {x: string.count(x) for x in '.·*'}
dot = max(dot_stats, key=dot_stats.get)
return morse_decode(string, dot=dot, dash=dash)
@pluginfunction('morse-encode', 'encode string to morse', ptypes.COMMAND, ratelimit_class=RATE_FUN | RATE_GLOBAL)
def command_morse_encode(argv, **args):
if not argv:
return {
'msg': args['reply_user'] + "usage: morse-encode <string>"
}
if len(argv) == 1 and argv[0] == 'that':
message_stack = args['stack']
if not message_stack[-1]:
return
message = message_stack[-1]['body']
else:
message = ' '.join(argv)
return {
'msg': args['reply_user'] + ': %s' % morse_encode(message)
}
@pluginfunction('morse-decode', 'decode morse encoded string', ptypes.COMMAND, ratelimit_class=RATE_FUN | RATE_GLOBAL)
def command_morse_decode(argv, **args):
if not argv:
return {
'msg': args['reply_user'] + "usage: morse-decode <string>"
}
if len(argv) == 1 and argv[0] == 'that':
message_stack = args['stack']
if not message_stack[-1]:
return
message = message_stack[-1]['body']
else:
message = ' '.join(argv)
decoded, errors = morse_decode(message, dot='·', dash='-')
return {
'msg': args['reply_user'] + ': %s (%d errors)' % (decoded, errors)
}

View File

@@ -39,6 +39,14 @@ def parse_mental_ill(**args):
} }
@pluginfunction('woof', '*puts sunglasses on*', ptypes.PARSE, ratelimit_class=RATE_NO_SILENCE | RATE_GLOBAL)
def command_woof(**args):
if 'who let the bots out' in args['data']:
return {
'msg': 'beeep! beep! beep! beep! beep!'
}
@pluginfunction('debbug', 'parse Debian bug numbers', ptypes.PARSE, ratelimit_class=RATE_NO_SILENCE | RATE_GLOBAL) @pluginfunction('debbug', 'parse Debian bug numbers', ptypes.PARSE, ratelimit_class=RATE_NO_SILENCE | RATE_GLOBAL)
def parse_debbug(**args): def parse_debbug(**args):
bugs = re.findall(r'#(\d{4,})', args['data']) bugs = re.findall(r'#(\d{4,})', args['data'])
@@ -122,8 +130,10 @@ def parse_slash_me(**args):
} }
@pluginfunction("recognize_bots", "got ya", ptypes.PARSE) @pluginfunction("recognize_bots", "got ya", ptypes.PARSE, enabled=False)
def recognize_bots(**args): def recognize_bots(**args):
# disabled until channel separation
return
unique_standard_phrases = ( unique_standard_phrases = (
'independent bot and have nothing to do with other artificial intelligence systems', 'independent bot and have nothing to do with other artificial intelligence systems',
'new Debian Security Announce', 'new Debian Security Announce',
@@ -184,3 +194,10 @@ def resolve_url_title(**args):
'msg': out 'msg': out
} }
@pluginfunction('doctor', 'parse doctor', ptypes.PARSE, ratelimit_class=RATE_FUN | RATE_GLOBAL)
def parse_doctor(**args):
if 'doctor' in args['data'].lower() or 'doktor' in args['data'].lower():
return {
'msg': 'ELIMINIEREN! ELIMINIEREN!'
}

View File

@@ -22,6 +22,8 @@ def translate(argv, **args):
if not api_key: if not api_key:
return return
message_stack = args['stack'] message_stack = args['stack']
if not message_stack[-1]:
return
last_message = message_stack[-1]['body'] last_message = message_stack[-1]['body']
data = { data = {
'q': last_message, 'q': last_message,

View File

@@ -7,10 +7,14 @@ import re
import shlex import shlex
import sys import sys
import time import time
from collections import deque
from lxml import etree from lxml import etree
import requests import requests
from sleekxmpp.plugins import PluginNotFound
import plugins # force initialization
from plugin_system import plugin_storage, ptypes, plugin_enabled_get from plugin_system import plugin_storage, ptypes, plugin_enabled_get
from rate_limit import rate_limit_classes, RATE_GLOBAL, RATE_CHAT, RATE_EVENT, rate_limit from rate_limit import rate_limit_classes, RATE_GLOBAL, RATE_CHAT, RATE_EVENT, rate_limit
@@ -34,7 +38,7 @@ class UrlBot(IdleBot):
self.hist_ts = {p: [] for p in rate_limit_classes} self.hist_ts = {p: [] for p in rate_limit_classes}
self.hist_flag = {p: True for p in rate_limit_classes} self.hist_flag = {p: True for p in rate_limit_classes}
self.message_stack = [] self.message_stack = {str(room): deque(maxlen=5) for room in self.rooms}
self.add_event_handler('message', self.message) self.add_event_handler('message', self.message)
self.priority = 100 self.priority = 100
@@ -42,6 +46,9 @@ class UrlBot(IdleBot):
for room in self.rooms: for room in self.rooms:
self.add_event_handler('muc::%s::got_online' % room, self.muc_online) self.add_event_handler('muc::%s::got_online' % room, self.muc_online)
dsa_plugin = list(filter(lambda x: x.plugin_name == 'dsa-watcher', plugin_storage[ptypes.COMMAND]))[0]
self._run_action(dsa_plugin(), dsa_plugin, None)
def muc_message(self, msg_obj): def muc_message(self, msg_obj):
""" """
Handle muc messages, return if irrelevant content or die by hangup. Handle muc messages, return if irrelevant content or die by hangup.
@@ -107,7 +114,10 @@ class UrlBot(IdleBot):
other_bots = config.runtimeconf_get("other_bots") other_bots = config.runtimeconf_get("other_bots")
if not other_bots: if not other_bots:
return False return False
try:
users = self.plugin['xep_0045'].getRoster(room) users = self.plugin['xep_0045'].getRoster(room)
except PluginNotFound:
users = []
return set(users).intersection(set(other_bots)) return set(users).intersection(set(other_bots))
def _prevent_panic(message, room): def _prevent_panic(message, room):
@@ -196,9 +206,8 @@ class UrlBot(IdleBot):
except Exception as e: except Exception as e:
self.logger.exception(e) self.logger.exception(e)
finally: finally:
if len(self.message_stack) > 4: if msg_obj['from'].bare in self.rooms:
self.message_stack.pop(0) self.message_stack[msg_obj['from'].bare].append(msg_obj)
self.message_stack.append(msg_obj)
def handle_muc_online(self, msg_obj): def handle_muc_online(self, msg_obj):
""" """
@@ -268,7 +277,7 @@ class UrlBot(IdleBot):
reply_user=reply_user, reply_user=reply_user,
msg_obj=msg_obj, msg_obj=msg_obj,
argv=words[2:] if len(words) > 1 else [], argv=words[2:] if len(words) > 1 else [],
stack=self.message_stack stack=self.message_stack.get(msg_obj['from'].bare, [])
) )
if ret: if ret:
@@ -348,7 +357,8 @@ class UrlBot(IdleBot):
args=command[1], args=command[1],
action_runner=self._run_action, action_runner=self._run_action,
plugin=plugin, plugin=plugin,
msg_obj=msg_obj msg_obj=msg_obj,
mutex=event.get('mutex')
) )
if 'msg' in action and rate_limit(RATE_CHAT | plugin.ratelimit_class): if 'msg' in action and rate_limit(RATE_CHAT | plugin.ratelimit_class):