diff --git a/examples/data/config/PubSubClient.json b/examples/data/config/PubSubClient.json new file mode 100644 index 0000000..e6b6647 --- /dev/null +++ b/examples/data/config/PubSubClient.json @@ -0,0 +1,5 @@ +{ + "servers": ["127.0.0.1:7100"], + "subscriptions": ["pyircbot_send"], + "publish": "pyircbot_{}" +} diff --git a/pyircbot/modulebase.py b/pyircbot/modulebase.py index e9739c0..2eba721 100644 --- a/pyircbot/modulebase.py +++ b/pyircbot/modulebase.py @@ -78,6 +78,10 @@ class ModuleBase: if configPath is not None: self.config = PyIRCBot.load(configPath) + def onenable(self): + """Called when the module is enabled""" + pass + def ondisable(self): """Called when the module should be disabled. Your module should do any sort of clean-up operations here like ending child threads or saving data files. diff --git a/pyircbot/modules/PubSubClient.py b/pyircbot/modules/PubSubClient.py new file mode 100644 index 0000000..3408645 --- /dev/null +++ b/pyircbot/modules/PubSubClient.py @@ -0,0 +1,102 @@ +""" +.. module::PubSubClient + :synopsis: connect to a message bus and act as a message relay +.. moduleauthor::Dave Pedu +""" + +from pyircbot.modulebase import ModuleBase, hook +from msgbus.client import MsgbusSubClient # see http://gitlab.davepedu.com/dave/pymsgbus +from threading import Thread +from json import dumps, loads +from time import sleep +from zmq.error import Again + + +class PubSubClient(ModuleBase): + def __init__(self, bot, moduleName): + ModuleBase.__init__(self, bot, moduleName) + self.host, self.port = self.config.get("servers")[0].split(":") + self.bus = None + self.bus_listener_thread = Thread(target=self.bus_listener) + self.bus_listener_thread.daemon = True + self.bus_listener_thread.start() + + def bus_listener(self): + sleep(3) + while True:#TODO clean exit onenable/ondisable etc + if not self.bus: + sleep(0.01) + continue + try: + channel, message = self.bus.recv(block=False) + except Again: + sleep(0.01) + continue + print(channel, "--", message) + tag, subcommand, message = message.split(" ", 2) + if tag != "default": + continue + + if subcommand == "privmsg": + dest, message = loads(message) + self.bot.act_PRIVMSG(dest, message) + + def publish(self, subchannel, message): + self.bus.pub(self.config.get("publish").format(subchannel), "{} {}".format("default", message)) + + @hook("PRIVMSG") + def bus_privmsg(self, msg): + # msg.command msg.args msg.prefix msg.trailing + self.publish("privmsg", dumps([msg.args, msg.prefix[0], msg.trailing, {"prefix": msg.prefix}])) + + @hook("JOIN") + def bus_join(self, msg): + # msg.command msg.args msg.prefix msg.trailing + self.publish("join", dumps([msg.prefix[0], msg.trailing, {"prefix": msg.prefix}])) + + @hook("PART") + def bus_part(self, msg): + # msg.command msg.args msg.prefix msg.trailing + self.publish("part", dumps([msg.args, msg.prefix[0], msg.trailing, {"prefix": msg.prefix}])) + + def onenable(self): + self.bus = MsgbusSubClient(self.host, int(self.port)) + for channel in self.config.get("subscriptions"): + self.bus.sub(channel) + self.publish("sys", "online") + + def ondisable(self): + self.log.warning("clean it up") + self.publish("sys", "offline") + self.bus.close() + +""" + +Bot connects to the bus: + + pyircbot_sys default online + +Bot disconnects from the bus: + + pyircbot_sys default offline + +Bot relaying a privmsg: + + pyircbot_privmsg default [["#clonebot"], "dave-irccloud", "message text", + {"prefix": ["dave-irccloud", "sid36094", "Clk-247B1F43.irccloud.com"]}] + +User parts a channel: + + pyircbot_part default [["#clonebot"], "dave-irccloud", "part msg", + {"prefix": ["dave-irccloud", "sid36094", "Clk-247B1F43.irccloud.com"]}] + +User joins a channel: + + pyircbot_join default ["dave-irccloud", "#clonebot", + {"prefix": ["dave-irccloud", "sid36094", "Clk-247B1F43.irccloud.com"]}] + +# Client sending a message that the bot will relay + + pyircbot_send default privmsg ["#clonebot", "asdf1234"] + +""" diff --git a/pyircbot/pyircbot.py b/pyircbot/pyircbot.py index 225a6c8..4f3eb64 100644 --- a/pyircbot/pyircbot.py +++ b/pyircbot/pyircbot.py @@ -182,6 +182,7 @@ class PyIRCBot(object): self.moduleInstances[name] = getattr(self.modules[name], name)(self, name) " load hooks " self.loadModuleHooks(self.moduleInstances[name]) + self.moduleInstances[name].onenable() def unloadmodule(self, name): """Deactivate a module.