Source code for cslbot.helpers.server
# -*- coding: utf-8 -*-
# Copyright (C) 2013-2015 Samuel Damashek, Peter Foley, James Forcier, Srijay Kasturi, Reed Koser, Christopher Reffett, and Fox Wilson
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import socketserver
from . import backtrace, reloader
WELCOME = """
Welcome to the IRCbot console.
Copyright (C) 2013-2015 Samuel Damashek, Peter Foley, James Forcier, Srijay Kasturi, Reed Koser, Christopher Reffett, and Fox Wilson
Licensed under the GNU GPL version 2.
Type "help" for a list of commands.
"""
HELP = """
help\t\t\tshow this help
admins\t\t\tshow the list of admins
reload\t\t\treload the bot
raw\t\t\tenter raw mode
endraw\t\t\texit raw mode
quit\t\t\tquit the console session
"""
[docs]def init_server(bot):
port = bot.config.getint('core', 'serverport')
try:
server = BotNetServer(('localhost', port), BotNetHandler)
except OSError as ex:
bot.shutdown_mp()
if ex.errno == 98:
raise Exception("Please make sure that there is no other service running on port %d" % port)
else:
raise ex
server.bot = bot
bot.handler.workers.start_thread(server.serve_forever)
return server
[docs]class BotNetServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
allow_reuse_address = True
[docs]class BotNetHandler(socketserver.BaseRequestHandler):
[docs] def get_data(self):
size = 4096
msg = "".encode()
while True:
data = self.request.recv(size)
msg += data
if len(data) != size:
break
return msg.decode()
[docs] def handle_cmd(self, cmd, bot, send):
if cmd[0] == "help":
send(HELP)
elif cmd[0] == "admins":
admins = ", ".join(bot.handler.admins.keys())
send("%s\n" % admins)
elif cmd[0] == "reload":
cmdargs = cmd[1] if len(cmd) > 1 else ''
ctrlchan = bot.config['core']['ctrlchan']
bot.reload_event.set()
if reloader.do_reload(bot, ctrlchan, cmdargs, send):
bot.server = init_server(bot)
bot.reload_event.clear()
send("Aye Aye Capt'n\n")
bot.connection.privmsg(ctrlchan, "Aye Aye Capt'n (triggered from server)")
self.request.close()
return False
elif cmd[0] == "raw":
while cmd[0] != "endraw":
send("ircbot-raw> ")
cmd = self.get_data().strip()
if cmd == "endraw":
return False
bot.handler.connection.send_raw(cmd)
elif cmd[0] == "quit":
send("Goodbye.\n")
self.request.close()
return False
else:
send("Unknown command. Type help for more info.\n")
return True
[docs] def handle(self):
try:
def send(msg):
self.request.send(msg.encode())
bot = self.server.bot
send("Password: ")
msg = self.get_data().splitlines()
ctrlpass = bot.config['auth']['ctrlpass']
if not msg or msg[0].strip() != ctrlpass:
send("Incorrect password.\n")
self.request.close()
return
if len(msg) > 1:
msg = list(reversed(msg[1:]))
end = len(msg)
send("\n")
else:
send(WELCOME)
end = 0
while True:
if end:
cmd = msg[end - 1].strip().split()
end -= 1
else:
try:
send("ircbot> ")
cmd = self.get_data().strip().split()
except BrokenPipeError:
# connection has been closed
return
if not cmd:
continue
if not self.handle_cmd(cmd, bot, send):
break
except Exception as ex:
msg, _ = backtrace.output_traceback(ex)
ctrlchan = bot.config['core']['ctrlchan']
send('%s\n' % msg)
bot.connection.privmsg(ctrlchan, msg)