plugin loader, graceful shutdown!
This commit is contained in:
parent
9d0f9248ff
commit
e6318fe725
7 changed files with 136 additions and 133 deletions
15
cloudbot.py
15
cloudbot.py
|
@ -1,6 +1,5 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# we import bot as _bot for now, for legacy reasons
|
from core import bot
|
||||||
from core import bot as _bot
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -12,17 +11,17 @@ os.chdir(sys.path[0] or '.') # do stuff relative to the install directory
|
||||||
print 'CloudBot REFRESH <http://git.io/cloudbotirc>'
|
print 'CloudBot REFRESH <http://git.io/cloudbotirc>'
|
||||||
|
|
||||||
def exit_gracefully(signum, frame):
|
def exit_gracefully(signum, frame):
|
||||||
bot.stop()
|
cloudbot.stop()
|
||||||
|
|
||||||
# store the original SIGINT handler
|
# store the original SIGINT handler
|
||||||
original_sigint = signal.getsignal(signal.SIGINT)
|
original_sigint = signal.getsignal(signal.SIGINT)
|
||||||
signal.signal(signal.SIGINT, exit_gracefully)
|
signal.signal(signal.SIGINT, exit_gracefully)
|
||||||
|
|
||||||
# create new bot object
|
# create new bot object
|
||||||
bot = _bot.Bot("cloudbot")
|
cloudbot = bot.Bot()
|
||||||
bot.logger.debug("Bot initalized, starting main loop.")
|
cloudbot.logger.debug("Bot initalized, starting main loop.")
|
||||||
|
|
||||||
while bot.running:
|
while cloudbot.running:
|
||||||
bot.loop()
|
cloudbot.loop()
|
||||||
|
|
||||||
bot.logger.debug("Stopped main loop.")
|
cloudbot.logger.debug("Stopped main loop.")
|
||||||
|
|
37
core/bot.py
37
core/bot.py
|
@ -4,8 +4,9 @@ import sys
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import Queue
|
import Queue
|
||||||
|
import collections
|
||||||
|
|
||||||
from core import config, irc, loader, main
|
from core import config, irc, main, loader
|
||||||
|
|
||||||
|
|
||||||
def clean_name(n):
|
def clean_name(n):
|
||||||
|
@ -14,9 +15,8 @@ def clean_name(n):
|
||||||
|
|
||||||
|
|
||||||
class Bot(object):
|
class Bot(object):
|
||||||
def __init__(self, name):
|
def __init__(self):
|
||||||
# basic variables
|
# basic variables
|
||||||
self.name = name
|
|
||||||
self.start_time = time.time()
|
self.start_time = time.time()
|
||||||
self.running = True
|
self.running = True
|
||||||
|
|
||||||
|
@ -29,20 +29,23 @@ class Bot(object):
|
||||||
self.connect()
|
self.connect()
|
||||||
|
|
||||||
# run plugin loader
|
# run plugin loader
|
||||||
self.logger.debug("Starting plugin reloader.")
|
self.plugins = collections.defaultdict(list)
|
||||||
loader.reload(self, init=True)
|
self.threads = {}
|
||||||
self.logger.debug("Plugin reloader started.")
|
self.loader = loader.PluginLoader(self)
|
||||||
|
|
||||||
|
|
||||||
def stop(self, reason=None):
|
def stop(self, reason=None):
|
||||||
"""quits all networks and shuts the bot down"""
|
"""quits all networks and shuts the bot down"""
|
||||||
|
|
||||||
self.logger.info("Stopping bot.")
|
self.logger.info("Stopping bot.")
|
||||||
self.running = False
|
self.running = False
|
||||||
|
|
||||||
# wait for the bot loop to stop
|
# wait for the bot loop to stop
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
self.config.observer.stop()
|
self.config.observer.stop()
|
||||||
self.logger.debug("Config reloader stopped.")
|
self.logger.debug("Stopping config reloader.")
|
||||||
|
|
||||||
|
self.loader.stop()
|
||||||
|
self.logger.debug("Stopping plugin loader.")
|
||||||
|
|
||||||
for name, connection in self.connections.iteritems():
|
for name, connection in self.connections.iteritems():
|
||||||
# TODO: end connections properly
|
# TODO: end connections properly
|
||||||
|
@ -59,9 +62,9 @@ class Bot(object):
|
||||||
logging.shutdown()
|
logging.shutdown()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
|
||||||
def loop(self):
|
def loop(self):
|
||||||
"""reloads plugins, then recives input from the IRC engine and processes it"""
|
"""recieves input from the IRC engine and processes it"""
|
||||||
loader.reload(self) # TODO: new plugin loader
|
|
||||||
|
|
||||||
for conn in self.connections.itervalues():
|
for conn in self.connections.itervalues():
|
||||||
try:
|
try:
|
||||||
|
@ -96,10 +99,11 @@ class Bot(object):
|
||||||
port = port, channels = conf['channels'])
|
port = port, channels = conf['channels'])
|
||||||
self.logger.debug("({}) Created connection.".format(name))
|
self.logger.debug("({}) Created connection.".format(name))
|
||||||
|
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
"""create the logger and config objects"""
|
"""create the logger and config objects"""
|
||||||
# logging
|
# logging
|
||||||
self.logger = self.get_logger()
|
self.logger = self.new_logger()
|
||||||
self.logger.debug("Logging engine started.")
|
self.logger.debug("Logging engine started.")
|
||||||
|
|
||||||
# data folder
|
# data folder
|
||||||
|
@ -110,17 +114,12 @@ class Bot(object):
|
||||||
self.logger.debug("Created data folder.")
|
self.logger.debug("Created data folder.")
|
||||||
|
|
||||||
# config
|
# config
|
||||||
self.config = self.get_config()
|
self.config = config.Config(self.logger)
|
||||||
self.logger.debug("Config object created.")
|
self.logger.debug("Config object created.")
|
||||||
|
|
||||||
|
|
||||||
def get_config(self):
|
def new_logger(self):
|
||||||
"""create and return the config object"""
|
"""create and return a new logger object"""
|
||||||
return config.Config(self.logger)
|
|
||||||
|
|
||||||
|
|
||||||
def get_logger(self):
|
|
||||||
"""create and return the logger object"""
|
|
||||||
# create logger
|
# create logger
|
||||||
logger = logging.getLogger("cloudbot")
|
logger = logging.getLogger("cloudbot")
|
||||||
logger.setLevel(logging.DEBUG)
|
logger.setLevel(logging.DEBUG)
|
||||||
|
|
|
@ -14,10 +14,10 @@ class Config(dict):
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.update(*args, **kwargs)
|
self.update(*args, **kwargs)
|
||||||
|
|
||||||
# load self
|
# populate self with config data
|
||||||
self.load_config()
|
self.load_config()
|
||||||
|
|
||||||
# start reloader
|
# start watcher
|
||||||
self.watcher()
|
self.watcher()
|
||||||
|
|
||||||
def load_config(self):
|
def load_config(self):
|
||||||
|
@ -40,6 +40,7 @@ class Config(dict):
|
||||||
|
|
||||||
|
|
||||||
def watcher(self):
|
def watcher(self):
|
||||||
|
self.logger.debug("Starting config reloader.")
|
||||||
pattern = "*{}".format(self.filename)
|
pattern = "*{}".format(self.filename)
|
||||||
event_handler = ConfigReloader(self, patterns=[pattern])
|
event_handler = ConfigReloader(self, patterns=[pattern])
|
||||||
self.observer = Observer()
|
self.observer = Observer()
|
||||||
|
|
25
core/irc.py
25
core/irc.py
|
@ -33,6 +33,7 @@ class RecieveThread(threading.Thread):
|
||||||
self.input_queue = input_queue
|
self.input_queue = input_queue
|
||||||
self.socket = socket
|
self.socket = socket
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
|
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
|
|
||||||
def recv_from_socket(self, nbytes):
|
def recv_from_socket(self, nbytes):
|
||||||
|
@ -97,12 +98,14 @@ class SendThread(threading.Thread):
|
||||||
self.output_queue = output_queue
|
self.output_queue = output_queue
|
||||||
self.conn_name = conn_name
|
self.conn_name = conn_name
|
||||||
self.socket = socket
|
self.socket = socket
|
||||||
|
|
||||||
|
self.shutdown = False
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
while True:
|
while not self.shutdown:
|
||||||
line = self.output_queue.get().splitlines()[0][:500]
|
line = self.output_queue.get().splitlines()[0][:500]
|
||||||
print u"{}> {}".format(self.conn_name, line)
|
print u"[{}]> {}".format(self.conn_name.upper(), line)
|
||||||
self.output_buffer += line.encode('utf-8', 'replace') + '\r\n'
|
self.output_buffer += line.encode('utf-8', 'replace') + '\r\n'
|
||||||
while self.output_buffer:
|
while self.output_buffer:
|
||||||
sent = self.socket.send(self.output_buffer)
|
sent = self.socket.send(self.output_buffer)
|
||||||
|
@ -115,6 +118,7 @@ class ParseThread(threading.Thread):
|
||||||
self.input_queue = input_queue # lines that were received
|
self.input_queue = input_queue # lines that were received
|
||||||
self.output_queue = output_queue # lines to be sent out
|
self.output_queue = output_queue # lines to be sent out
|
||||||
self.parsed_queue = parsed_queue # lines that have been parsed
|
self.parsed_queue = parsed_queue # lines that have been parsed
|
||||||
|
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
@ -166,15 +170,17 @@ class Connection(object):
|
||||||
self.socket.connect((self.host, self.port))
|
self.socket.connect((self.host, self.port))
|
||||||
|
|
||||||
self.recieve_thread = RecieveThread(self.socket, self.input_queue, self.timeout)
|
self.recieve_thread = RecieveThread(self.socket, self.input_queue, self.timeout)
|
||||||
|
self.recieve_thread.daemon = True
|
||||||
self.recieve_thread.start()
|
self.recieve_thread.start()
|
||||||
|
|
||||||
self.send_thread = SendThread(self.socket, self.conn_name, self.output_queue)
|
self.send_thread = SendThread(self.socket, self.conn_name, self.output_queue)
|
||||||
|
self.send_thread.daemon = True
|
||||||
self.send_thread.start()
|
self.send_thread.start()
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.recieve_thread.stop()
|
self.send_thread.shutdown = True
|
||||||
self.send_thread.stop()
|
time.sleep(.1)
|
||||||
self.socket.disconnect()
|
self.socket.close()
|
||||||
|
|
||||||
|
|
||||||
class SSLConnection(Connection):
|
class SSLConnection(Connection):
|
||||||
|
@ -222,17 +228,12 @@ class IRC(object):
|
||||||
|
|
||||||
self.parse_thread = ParseThread(self.input_queue, self.output_queue,
|
self.parse_thread = ParseThread(self.input_queue, self.output_queue,
|
||||||
self.parsed_queue)
|
self.parsed_queue)
|
||||||
|
self.parse_thread.daemon = True
|
||||||
self.parse_thread.start()
|
self.parse_thread.start()
|
||||||
|
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.parse_thread.stop()
|
self.connection.stop()
|
||||||
self.parse_thread.stop()
|
|
||||||
|
|
||||||
def connect(self):
|
|
||||||
self.conn = self.create_connection()
|
|
||||||
self.conn_thread = thread.start_new_thread(self.conn.run, ())
|
|
||||||
|
|
||||||
|
|
||||||
def set_pass(self, password):
|
def set_pass(self, password):
|
||||||
if password:
|
if password:
|
||||||
|
|
144
core/loader.py
144
core/loader.py
|
@ -1,19 +1,15 @@
|
||||||
import collections
|
|
||||||
import glob
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import glob
|
||||||
|
import collections
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
from watchdog.observers import Observer
|
||||||
|
from watchdog.tricks import Trick
|
||||||
|
|
||||||
from core import main
|
from core import main
|
||||||
|
|
||||||
|
|
||||||
if 'mtimes' not in globals():
|
|
||||||
mtimes = {}
|
|
||||||
|
|
||||||
if 'lastfiles' not in globals():
|
|
||||||
lastfiles = set()
|
|
||||||
|
|
||||||
|
|
||||||
def make_signature(f):
|
def make_signature(f):
|
||||||
return f.func_code.co_filename, f.func_name, f.func_code.co_firstlineno
|
return f.func_code.co_filename, f.func_name, f.func_code.co_firstlineno
|
||||||
|
|
||||||
|
@ -32,108 +28,112 @@ def format_plug(plug, kind='', lpad=0):
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
def reload(bot, init=False):
|
class PluginLoader(object):
|
||||||
changed = False
|
def __init__(self, bot):
|
||||||
|
self.observer = Observer()
|
||||||
|
self.path = os.path.abspath("plugins")
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
if init:
|
self.event_handler = EventHandler(self, patterns=["*.py"])
|
||||||
bot.plugins = collections.defaultdict(list)
|
self.observer.schedule(self.event_handler, self.path, recursive=False)
|
||||||
bot.threads = {}
|
self.observer.start()
|
||||||
|
|
||||||
fileset = set(glob.glob(os.path.join('plugins', '*.py')))
|
self.load_all()
|
||||||
|
|
||||||
# remove deleted/moved plugins
|
|
||||||
for name, data in bot.plugins.iteritems():
|
|
||||||
bot.plugins[name] = [x for x in data if x[0]._filename in fileset]
|
|
||||||
|
|
||||||
for filename in list(mtimes):
|
def stop(self):
|
||||||
if filename not in fileset and filename not in core_fileset:
|
self.observer.stop()
|
||||||
mtimes.pop(filename)
|
|
||||||
|
|
||||||
for func, handler in list(bot.threads.iteritems()):
|
|
||||||
if func._filename not in fileset:
|
|
||||||
main.handler.stop()
|
|
||||||
del bot.threads[func]
|
|
||||||
|
|
||||||
# compile new plugins
|
def load_all(self):
|
||||||
for filename in fileset:
|
files = set(glob.glob(os.path.join(self.path, '*.py')))
|
||||||
mtime = os.stat(filename).st_mtime
|
for f in files:
|
||||||
if mtime != mtimes.get(filename):
|
self.load_file(f, loaded_all=True)
|
||||||
mtimes[filename] = mtime
|
self.rebuild()
|
||||||
|
|
||||||
changed = True
|
|
||||||
|
def load_file(self, path, loaded_all=False):
|
||||||
|
filename = os.path.basename(path)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
code = compile(open(filename, 'U').read(), filename, 'exec')
|
code = compile(open(path, 'U').read(), filename, 'exec')
|
||||||
namespace = {}
|
namespace = {}
|
||||||
eval(code, namespace)
|
eval(code, namespace)
|
||||||
except Exception:
|
except Exception:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
continue
|
return
|
||||||
|
|
||||||
# remove plugins already loaded from this filename
|
# remove plugins already loaded from this filename
|
||||||
for name, data in bot.plugins.iteritems():
|
for name, data in self.bot.plugins.iteritems():
|
||||||
bot.plugins[name] = [x for x in data
|
self.bot.plugins[name] = [x for x in data
|
||||||
if x[0]._filename != filename]
|
if x[0]._filename != filename]
|
||||||
|
|
||||||
for func, handler in list(bot.threads.iteritems()):
|
for func, handler in list(self.bot.threads.iteritems()):
|
||||||
if func._filename == filename:
|
if func._filename == filename:
|
||||||
handler.stop()
|
handler.stop()
|
||||||
del bot.threads[func]
|
del self.bot.threads[func]
|
||||||
|
|
||||||
for obj in namespace.itervalues():
|
for obj in namespace.itervalues():
|
||||||
if hasattr(obj, '_hook'): # check for magic
|
if hasattr(obj, '_hook'): # check for magic
|
||||||
if obj._thread:
|
if obj._thread:
|
||||||
bot.threads[obj] = main.Handler(bot, obj)
|
self.bot.threads[obj] = main.Handler(self.bot, obj)
|
||||||
|
|
||||||
for type, data in obj._hook:
|
for type, data in obj._hook:
|
||||||
bot.plugins[type] += [data]
|
self.bot.plugins[type] += [data]
|
||||||
|
self.bot.logger.info("Loaded plugin: {} ({})".format(format_plug(data), type))
|
||||||
|
|
||||||
if not init:
|
if not loaded_all:
|
||||||
print '### new plugin (type: %s) loaded:' % \
|
self.rebuild()
|
||||||
type, format_plug(data)
|
|
||||||
|
|
||||||
if changed:
|
|
||||||
bot.commands = {}
|
def unload_file(self, path):
|
||||||
for plug in bot.plugins['command']:
|
filename = os.path.basename(path)
|
||||||
|
self.bot.logger.info("Unloading plugins from: {}".format(filename))
|
||||||
|
|
||||||
|
for plugin_type, plugins in self.bot.plugins.iteritems():
|
||||||
|
self.bot.plugins[plugin_type] = [x for x in plugins if x[0]._filename != filename]
|
||||||
|
|
||||||
|
for func, handler in list(self.bot.threads.iteritems()):
|
||||||
|
if func._filename == filename:
|
||||||
|
main.handler.stop()
|
||||||
|
del self.bot.threads[func]
|
||||||
|
|
||||||
|
|
||||||
|
def rebuild(self):
|
||||||
|
self.bot.commands = {}
|
||||||
|
for plug in self.bot.plugins['command']:
|
||||||
name = plug[1]['name'].lower()
|
name = plug[1]['name'].lower()
|
||||||
if not re.match(r'^\w+$', name):
|
if not re.match(r'^\w+$', name):
|
||||||
print '### ERROR: invalid command name "{}" ({})'.format(name, format_plug(plug))
|
print '### ERROR: invalid command name "{}" ({})'.format(name, format_plug(plug))
|
||||||
continue
|
continue
|
||||||
if name in bot.commands:
|
if name in self.bot.commands:
|
||||||
print "### ERROR: command '{}' already registered ({}, {})".format(name,
|
print "### ERROR: command '{}' already registered ({}, {})".format(name,
|
||||||
format_plug(bot.commands[name]),
|
format_plug(self.bot.commands[name]),
|
||||||
format_plug(plug))
|
format_plug(plug))
|
||||||
continue
|
continue
|
||||||
bot.commands[name] = plug
|
self.bot.commands[name] = plug
|
||||||
|
|
||||||
bot.events = collections.defaultdict(list)
|
self.bot.events = collections.defaultdict(list)
|
||||||
for func, args in bot.plugins['event']:
|
for func, args in self.bot.plugins['event']:
|
||||||
for event in args['events']:
|
for event in args['events']:
|
||||||
bot.events[event].append((func, args))
|
self.bot.events[event].append((func, args))
|
||||||
|
|
||||||
if init:
|
|
||||||
print ' plugin listing:'
|
|
||||||
|
|
||||||
if bot.commands:
|
class EventHandler(Trick):
|
||||||
# hack to make commands with multiple aliases
|
def __init__(self, loader, *args, **kwargs):
|
||||||
# print nicely
|
self.loader = loader
|
||||||
|
Trick.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
print ' command:'
|
|
||||||
commands = collections.defaultdict(list)
|
|
||||||
|
|
||||||
for name, (func, args) in bot.commands.iteritems():
|
def on_created(self, event):
|
||||||
commands[make_signature(func)].append(name)
|
self.loader.load_file(event.src_path)
|
||||||
|
|
||||||
for sig, names in sorted(commands.iteritems()):
|
def on_deleted(self, event):
|
||||||
names.sort(key=lambda x: (-len(x), x)) # long names first
|
self.loader.unload_file(event.src_path)
|
||||||
out = ' ' * 6 + '%s:%s:%s' % sig
|
|
||||||
out += ' ' * (50 - len(out)) + ', '.join(names)
|
|
||||||
print out
|
|
||||||
|
|
||||||
for kind, plugs in sorted(bot.plugins.iteritems()):
|
def on_modified(self, event):
|
||||||
if kind == 'command':
|
self.loader.load_file(event.src_path)
|
||||||
continue
|
|
||||||
print ' {}:'.format(kind)
|
def on_moved(self, event):
|
||||||
for plug in plugs:
|
self.loader.unload_file(event.src_path)
|
||||||
print format_plug(plug, kind=kind, lpad=6)
|
self.loader.load_file(event.dest_path)
|
||||||
print
|
|
||||||
|
|
|
@ -176,7 +176,7 @@ def main(bot, conn, out):
|
||||||
command = match_command(bot, trigger)
|
command = match_command(bot, trigger)
|
||||||
|
|
||||||
if isinstance(command, list): # multiple potential matches
|
if isinstance(command, list): # multiple potential matches
|
||||||
input = Input(conn, *out)
|
input = Input(bot, conn, *out)
|
||||||
input.notice("Did you mean {} or {}?".format
|
input.notice("Did you mean {} or {}?".format
|
||||||
(', '.join(command[:-1]), command[-1]))
|
(', '.join(command[:-1]), command[-1]))
|
||||||
elif command in bot.commands:
|
elif command in bot.commands:
|
||||||
|
@ -192,7 +192,7 @@ def main(bot, conn, out):
|
||||||
for func, args in bot.plugins['regex']:
|
for func, args in bot.plugins['regex']:
|
||||||
m = args['re'].search(inp.lastparam)
|
m = args['re'].search(inp.lastparam)
|
||||||
if m:
|
if m:
|
||||||
input = Input(conn, *out)
|
input = Input(bot, conn, *out)
|
||||||
input.inp = m
|
input.inp = m
|
||||||
|
|
||||||
dispatch(input, "regex", func, args)
|
dispatch(input, "regex", func, args)
|
||||||
|
|
|
@ -20,6 +20,7 @@ def invite(paraml, conn=None):
|
||||||
# Identify to NickServ (or other service)
|
# Identify to NickServ (or other service)
|
||||||
@hook.event('004')
|
@hook.event('004')
|
||||||
def onjoin(paraml, conn=None, bot=None):
|
def onjoin(paraml, conn=None, bot=None):
|
||||||
|
bot.logger.info("ONJOIN hook triggered.")
|
||||||
nickserv = conn.conf.get('nickserv')
|
nickserv = conn.conf.get('nickserv')
|
||||||
if nickserv:
|
if nickserv:
|
||||||
nickserv_password = nickserv.get('nickserv_password', '')
|
nickserv_password = nickserv.get('nickserv_password', '')
|
||||||
|
@ -39,14 +40,16 @@ def onjoin(paraml, conn=None, bot=None):
|
||||||
# Set bot modes
|
# Set bot modes
|
||||||
mode = conn.conf.get('mode')
|
mode = conn.conf.get('mode')
|
||||||
if mode:
|
if mode:
|
||||||
|
bot.logger.info('Setting bot mode: "{}"'.format(mode))
|
||||||
conn.cmd('MODE', [conn.nick, mode])
|
conn.cmd('MODE', [conn.nick, mode])
|
||||||
|
|
||||||
# Join config-defined channels
|
# Join config-defined channels
|
||||||
|
bot.logger.info('Joining channels.')
|
||||||
for channel in conn.channels:
|
for channel in conn.channels:
|
||||||
conn.join(channel)
|
conn.join(channel)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
print "Bot ready."
|
bot.logger.info("ONJOIN hook completed. Bot ready.")
|
||||||
|
|
||||||
|
|
||||||
@hook.event("KICK")
|
@hook.event("KICK")
|
||||||
|
@ -60,12 +63,12 @@ def onkick(paraml, conn=None, chan=None):
|
||||||
|
|
||||||
|
|
||||||
@hook.event("NICK")
|
@hook.event("NICK")
|
||||||
def onnick(paraml, conn=None, raw=None):
|
def onnick(paraml, bot=None, conn=None, raw=None):
|
||||||
old_nick = nick_re.search(raw).group(1)
|
old_nick = nick_re.search(raw).group(1)
|
||||||
new_nick = str(paraml[0])
|
new_nick = str(paraml[0])
|
||||||
if old_nick == conn.nick:
|
if old_nick == conn.nick:
|
||||||
conn.nick = new_nick
|
conn.nick = new_nick
|
||||||
print "Bot nick changed from '{}' to '{}'.".format(old_nick, new_nick)
|
bot.logger.info("Bot nick changed from '{}' to '{}'.".format(old_nick, new_nick))
|
||||||
|
|
||||||
|
|
||||||
@hook.singlethread
|
@hook.singlethread
|
||||||
|
|
Reference in a new issue