move IRC server settings to database
this is the first step in trying to get the bot to support multiple servers with different channels, countdown triggers, and so on this also ends up affecting some configuration around: * dispatch * markov * admin privmsg form
This commit is contained in:
@@ -3,23 +3,15 @@
|
||||
import logging
|
||||
import xmlrpc.client
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from django.shortcuts import render
|
||||
|
||||
from ircbot.forms import PrivmsgForm
|
||||
from ircbot.models import Alias, BotUser, IrcChannel, IrcPlugin
|
||||
|
||||
from ircbot.models import Alias, BotUser, IrcChannel, IrcPlugin, IrcServer
|
||||
|
||||
log = logging.getLogger('ircbot.admin')
|
||||
|
||||
|
||||
admin.site.register(Alias)
|
||||
admin.site.register(BotUser)
|
||||
admin.site.register(IrcChannel)
|
||||
admin.site.register(IrcPlugin)
|
||||
|
||||
|
||||
def send_privmsg(request):
|
||||
"""Send a privmsg over XML-RPC to the IRC bot."""
|
||||
if request.method == 'POST':
|
||||
@@ -28,7 +20,8 @@ def send_privmsg(request):
|
||||
target = form.cleaned_data['target']
|
||||
message = form.cleaned_data['message']
|
||||
|
||||
bot_url = 'http://{0:s}:{1:d}/'.format(settings.IRCBOT_XMLRPC_HOST, settings.IRCBOT_XMLRPC_PORT)
|
||||
bot_url = 'http://{0:s}:{1:d}/'.format(form.cleaned_data['xmlrpc_host'],
|
||||
form.cleaned_data['xmlrpc_port'])
|
||||
bot = xmlrpc.client.ServerProxy(bot_url, allow_none=True)
|
||||
bot.reply(None, message, False, target)
|
||||
form = PrivmsgForm()
|
||||
@@ -37,4 +30,11 @@ def send_privmsg(request):
|
||||
|
||||
return render(request, 'privmsg.html', {'form': form})
|
||||
|
||||
|
||||
admin.site.register(Alias)
|
||||
admin.site.register(BotUser)
|
||||
admin.site.register(IrcChannel)
|
||||
admin.site.register(IrcPlugin)
|
||||
admin.site.register(IrcServer)
|
||||
|
||||
admin.site.register_view('ircbot/privmsg/', "Ircbot - privmsg", view=send_privmsg, urlname='ircbot_privmsg')
|
||||
|
||||
@@ -22,7 +22,7 @@ from irc.dict import IRCDict
|
||||
import irc.modes
|
||||
|
||||
import ircbot.lib as ircbotlib
|
||||
from ircbot.models import Alias, IrcChannel, IrcPlugin
|
||||
from ircbot.models import Alias, IrcChannel, IrcPlugin, IrcServer
|
||||
|
||||
|
||||
log = logging.getLogger('ircbot.bot')
|
||||
@@ -54,6 +54,8 @@ class LenientServerConnection(irc.client.ServerConnection):
|
||||
|
||||
buffer_class = irc.buffer.LenientDecodingLineBuffer
|
||||
|
||||
server_config = None
|
||||
|
||||
def _prep_message(self, string):
|
||||
"""Override SimpleIRCClient._prep_message to add some logging."""
|
||||
log.debug("preparing message %s", string)
|
||||
@@ -163,7 +165,8 @@ class DrReactor(irc.client.Reactor):
|
||||
event.original_msg = what
|
||||
|
||||
# check if we were addressed or not
|
||||
all_nicks = '|'.join(settings.ADDITIONAL_NICK_MATCHES + [connection.get_nickname()])
|
||||
all_nicks = '|'.join(connection.server_config.additional_addressed_nicks.split('\n') +
|
||||
[connection.get_nickname()])
|
||||
addressed_pattern = r'^(({nicks})[:,]|@({nicks}))\s+(?P<addressed_msg>.*)'.format(nicks=all_nicks)
|
||||
match = re.match(addressed_pattern, what, re.IGNORECASE)
|
||||
if match:
|
||||
@@ -351,15 +354,16 @@ class IRCBot(irc.client.SimpleIRCClient):
|
||||
reactor_class = DrReactor
|
||||
splitter = "..."
|
||||
|
||||
def __init__(self, reconnection_interval=60):
|
||||
def __init__(self, server_name, reconnection_interval=60):
|
||||
"""Initialize bot."""
|
||||
super(IRCBot, self).__init__()
|
||||
|
||||
self.channels = IRCDict()
|
||||
self.plugins = []
|
||||
|
||||
# set up the server list
|
||||
self.server_list = settings.IRCBOT_SERVER_LIST
|
||||
self.server_config = IrcServer.objects.get(name=server_name)
|
||||
# the reactor made the connection, save the server reference in it since we pass that around
|
||||
self.connection.server_config = self.server_config
|
||||
|
||||
# set reconnection interval
|
||||
if not reconnection_interval or reconnection_interval < 0:
|
||||
@@ -367,8 +371,8 @@ class IRCBot(irc.client.SimpleIRCClient):
|
||||
self.reconnection_interval = reconnection_interval
|
||||
|
||||
# set basic stuff
|
||||
self._nickname = settings.IRCBOT_NICKNAME
|
||||
self._realname = settings.IRCBOT_REALNAME
|
||||
self._nickname = self.server_config.nickname
|
||||
self._realname = self.server_config.realname
|
||||
|
||||
# guess at nickmask. hopefully _on_welcome() will set this, but this should be
|
||||
# a pretty good guess if not
|
||||
@@ -395,7 +399,7 @@ class IRCBot(irc.client.SimpleIRCClient):
|
||||
getattr(self, 'handle_reload'), -20)
|
||||
|
||||
# load XML-RPC server
|
||||
self.xmlrpc = SimpleXMLRPCServer((settings.IRCBOT_XMLRPC_HOST, settings.IRCBOT_XMLRPC_PORT),
|
||||
self.xmlrpc = SimpleXMLRPCServer((self.server_config.xmlrpc_host, self.server_config.xmlrpc_port),
|
||||
requestHandler=IrcBotXMLRPCRequestHandler, allow_none=True)
|
||||
self.xmlrpc.register_introspection_functions()
|
||||
|
||||
@@ -414,16 +418,15 @@ class IRCBot(irc.client.SimpleIRCClient):
|
||||
self.jump_server()
|
||||
|
||||
def _connect(self):
|
||||
server = self.server_list[0]
|
||||
try:
|
||||
# build the connection factory as determined by IPV6/SSL settings
|
||||
if settings.IRCBOT_SSL:
|
||||
connect_factory = Factory(wrapper=ssl.wrap_socket, ipv6=settings.IRCBOT_IPV6)
|
||||
if self.server_config.use_ssl:
|
||||
connect_factory = Factory(wrapper=ssl.wrap_socket, ipv6=self.server_config.use_ipv6)
|
||||
else:
|
||||
connect_factory = Factory(ipv6=settings.IRCBOT_IPV6)
|
||||
connect_factory = Factory(ipv6=self.server_config.use_ipv6)
|
||||
|
||||
self.connect(server[0], server[1], self._nickname, server[2], ircname=self._realname,
|
||||
connect_factory=connect_factory)
|
||||
self.connect(self.server_config.hostname, self.server_config.port, self._nickname,
|
||||
self.server_config.password, ircname=self._realname, connect_factory=connect_factory)
|
||||
except irc.client.ServerConnectionError:
|
||||
pass
|
||||
|
||||
@@ -528,13 +531,13 @@ class IRCBot(irc.client.SimpleIRCClient):
|
||||
log.debug("welcome: %s", what)
|
||||
|
||||
# run automsg commands
|
||||
for cmd in settings.IRCBOT_POST_CONNECT_COMMANDS:
|
||||
for cmd in self.server_config.post_connect.split('\n'):
|
||||
# TODO NOTE: if the bot is sending something that changes the vhost
|
||||
# (like 'hostserv on') we don't pick it up
|
||||
self.connection.privmsg(cmd.split(' ')[0], ' '.join(cmd.split(' ')[1:]))
|
||||
|
||||
# sleep before doing autojoins
|
||||
time.sleep(settings.IRCBOT_SLEEP_BEFORE_AUTOJOIN_SECONDS)
|
||||
time.sleep(self.server_config.delay_before_joins)
|
||||
|
||||
for chan in IrcChannel.objects.filter(autojoin=True):
|
||||
log.info("autojoining %s", chan.name)
|
||||
@@ -584,7 +587,6 @@ class IRCBot(irc.client.SimpleIRCClient):
|
||||
if self.connection.is_connected():
|
||||
self.connection.disconnect(msg)
|
||||
|
||||
self.server_list.append(self.server_list.pop(0))
|
||||
self._connect()
|
||||
|
||||
def on_ctcp(self, c, e):
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
"""Forms for doing ircbot stuff."""
|
||||
|
||||
import logging
|
||||
|
||||
from django.forms import Form, CharField, Textarea
|
||||
from django.forms import CharField, Form, IntegerField, Textarea
|
||||
|
||||
log = logging.getLogger('markov.forms')
|
||||
log = logging.getLogger('ircbot.forms')
|
||||
|
||||
|
||||
class PrivmsgForm(Form):
|
||||
@@ -12,3 +11,5 @@ class PrivmsgForm(Form):
|
||||
|
||||
target = CharField()
|
||||
message = CharField(widget=Textarea)
|
||||
xmlrpc_host = CharField()
|
||||
xmlrpc_port = IntegerField()
|
||||
|
||||
@@ -17,8 +17,13 @@ class Command(BaseCommand):
|
||||
|
||||
help = "Start the IRC bot"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
"""Add arguments to the bot startup."""
|
||||
parser.add_argument('server_name')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
"""Start the IRC bot and spin forever."""
|
||||
irc = IRCBot()
|
||||
self.stdout.write(self.style.NOTICE(f"Starting up {options['server_name']} bot"))
|
||||
irc = IRCBot(options['server_name'])
|
||||
signal.signal(signal.SIGINT, irc.sigint_handler)
|
||||
irc.start()
|
||||
|
||||
32
ircbot/migrations/0015_ircserver.py
Normal file
32
ircbot/migrations/0015_ircserver.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# Generated by Django 3.1.2 on 2021-04-25 14:05
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ircbot', '0014_auto_20160116_1955'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='IrcServer',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=200, unique=True)),
|
||||
('hostname', models.CharField(max_length=200)),
|
||||
('port', models.PositiveSmallIntegerField(default=6667)),
|
||||
('password', models.CharField(blank=True, default=None, max_length=200, null=True)),
|
||||
('nickname', models.CharField(max_length=32)),
|
||||
('realname', models.CharField(blank=True, default='', max_length=32)),
|
||||
('additional_addressed_nicks', models.TextField(blank=True, default='', help_text='For e.g. BitlBee alternative nicks')),
|
||||
('use_ssl', models.BooleanField(default=False)),
|
||||
('use_ipv6', models.BooleanField(default=False)),
|
||||
('post_connect', models.TextField(blank=True, default='')),
|
||||
('delay_before_joins', models.PositiveSmallIntegerField(default=0)),
|
||||
('xmlrpc_host', models.CharField(default='localhost', max_length=200)),
|
||||
('xmlrpc_port', models.PositiveSmallIntegerField(default=13132)),
|
||||
],
|
||||
),
|
||||
]
|
||||
26
ircbot/migrations/0016_placeholder_ircserver.py
Normal file
26
ircbot/migrations/0016_placeholder_ircserver.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# Generated by Django 3.1.2 on 2021-04-25 04:11
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def create_placeholder_server(apps, schema_editor):
|
||||
"""Create the first server entry, to be configured by the admin."""
|
||||
IrcServer = apps.get_model('ircbot', 'IrcServer')
|
||||
IrcServer.objects.create(name='default', hostname='irc.example.org', port=6667)
|
||||
|
||||
|
||||
def delete_placeholder_server(apps, schema_editor):
|
||||
"""Remove the default server."""
|
||||
IrcServer = apps.get_model('ircbot', 'IrcServer')
|
||||
IrcServer.objects.filter(name='default').delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ircbot', '0015_ircserver'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(create_placeholder_server, delete_placeholder_server),
|
||||
]
|
||||
@@ -62,6 +62,33 @@ class BotUser(models.Model):
|
||||
return "{0:s} (Django user {1:s})".format(self.nickmask, self.user.username)
|
||||
|
||||
|
||||
class IrcServer(models.Model):
|
||||
"""Contain server information in an object, and help contextualize channels."""
|
||||
|
||||
name = models.CharField(max_length=200, unique=True)
|
||||
hostname = models.CharField(max_length=200)
|
||||
port = models.PositiveSmallIntegerField(default=6667)
|
||||
password = models.CharField(max_length=200, default=None, null=True, blank=True)
|
||||
|
||||
nickname = models.CharField(max_length=32)
|
||||
realname = models.CharField(max_length=32, default='', blank=True)
|
||||
additional_addressed_nicks = models.TextField(default='', blank=True,
|
||||
help_text="For e.g. BitlBee alternative nicks")
|
||||
|
||||
use_ssl = models.BooleanField(default=False)
|
||||
use_ipv6 = models.BooleanField(default=False)
|
||||
|
||||
post_connect = models.TextField(default='', blank=True)
|
||||
delay_before_joins = models.PositiveSmallIntegerField(default=0)
|
||||
|
||||
xmlrpc_host = models.CharField(max_length=200, default='localhost')
|
||||
xmlrpc_port = models.PositiveSmallIntegerField(default=13132)
|
||||
|
||||
def __str__(self):
|
||||
"""Provide string summary of the server."""
|
||||
return f"{self.name} ({self.hostname}/{self.port})"
|
||||
|
||||
|
||||
class IrcChannel(models.Model):
|
||||
"""Track channel settings."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user