From 86065610748ca1dba20b3aa74a5620736b434573 Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 27 Nov 2017 23:21:48 -0800 Subject: [PATCH] Add module touch reloading in pubsubbot --- bin/pubsubbot | 21 +++++++++++++++++++-- pyircbot/common.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/bin/pubsubbot b/bin/pubsubbot index 1201798..63944b3 100755 --- a/bin/pubsubbot +++ b/bin/pubsubbot @@ -10,6 +10,7 @@ import pyircbot import traceback from pyircbot.pyircbot import PrimitiveBot from pyircbot.irccore import IRCEvent, UserPrefix +from pyircbot.common import TouchReload from json import dumps @@ -109,6 +110,7 @@ if __name__ == "__main__": parser.add_argument("-p", "--port", default=7100, type=int, help="Msgbus server port") parser.add_argument("-n", "--name", default="default", help="bot name") parser.add_argument("--debug", action="store_true", help="increase logging level") + parser.add_argument("--touch-reload", action="store_true", help="reload modules on file modification") args = parser.parse_args() if args.debug: @@ -122,10 +124,25 @@ if __name__ == "__main__": bot = PyIRCBotSub(args.name, args.server, int(args.port), config) # Load modules in config - sys.path.append(os.path.dirname(pyircbot.__file__) + "/modules/") + moddir = os.path.join(os.path.dirname(pyircbot.__file__), "modules") + modpaths = [] + sys.path.append(moddir) for modulename in config["modules"]: - print("Load: ", modulename) bot.loadmodule(modulename) + modpaths.append(os.path.join(moddir, modulename + ".py")) + + if args.touch_reload: + def changed(path): + module_name = os.path.basename(path).split(".")[-2] + logging.warning("{} was modified, reloading".format(module_name)) + if module_name in bot.moduleInstances.keys(): # TODO fix shitty mystery results from redomodule in core + bot.redomodule(module_name) + else: + bot.loadmodule(module_name) + + reloader = TouchReload(modpaths, changed) + reloader.daemon = True + reloader.start() bot.run() diff --git a/pyircbot/common.py b/pyircbot/common.py index 63f59da..254ce9b 100644 --- a/pyircbot/common.py +++ b/pyircbot/common.py @@ -2,6 +2,9 @@ from time import time from math import floor from json import load as json_load from collections import namedtuple +from time import sleep +import os +from threading import Thread ParsedCommand = namedtuple("ParsedCommand", "command args args_str message") @@ -46,6 +49,31 @@ class burstbucket(object): return self.bucket_period - since_fill +class TouchReload(Thread): + def __init__(self, filepaths, do, resolution=0.75): + """ + Given a list of module files, call a lambda if the modification times changes + :param filepaths: list of filepaths + :param do: lambda to call with the altered filepath + """ + super().__init__() + self.files = [[os.path.normpath(i), None] for i in filepaths] + self.do = do + self.sleep = resolution + + def run(self): + while True: + for num, (path, mtime) in enumerate(self.files): + new_mtime = os.stat(path).st_mtime + if mtime is None: + self.files[num][1] = new_mtime + continue + if mtime != new_mtime: + self.files[num][1] = new_mtime + self.do(path) + sleep(self.sleep) + + def messageHasCommand(command, message, requireArgs=False): """Check if a message has a command with or without args in it