pyircbot/pyircbot/modules/PubSubClient.py

114 lines
3.8 KiB
Python
Raw Normal View History

2017-09-18 19:56:22 -07:00
"""
.. module::PubSubClient
:synopsis: connect to a message bus and act as a message relay
.. moduleauthor::Dave Pedu <dave@davepedu.com>
"""
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
2017-09-18 20:12:08 -07:00
from traceback import print_exc
import re
COMMAND_RE = re.compile(r'\.(([a-zA-Z0-9]{1,16})(\s|$))(\s.+)?')
2017-09-18 19:56:22 -07:00
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):
2017-09-21 21:09:35 -07:00
"""
Listen to the bus for send messages and act on recv
"""
2017-09-18 19:56:22 -07:00
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
2017-09-18 20:12:08 -07:00
try:
print(channel, "--", message)
2017-09-21 21:09:35 -07:00
name, subcommand, message = message.split(" ", 2)
if name != self.config.get("name", "default") and name != "default":
2017-09-18 20:12:08 -07:00
continue
if subcommand == "privmsg":
dest, message = loads(message)
self.bot.act_PRIVMSG(dest, message)
except:
print_exc()
2017-09-18 19:56:22 -07:00
def publish(self, subchannel, message):
2017-09-21 21:09:35 -07:00
"""
Abstracted callback for proxying irc messages to the bs
:param subchannel: event type such as "privmsg"
:type subchannel: str
:param message: message body
:type message: str
"""
2017-09-18 19:56:22 -07:00
self.bus.pub(self.config.get("publish").format(subchannel), "{} {}".format("default", message))
@hook("PRIVMSG")
2017-11-27 18:58:20 -08:00
def bus_privmsg(self, msg, cmd):
2017-09-21 21:09:35 -07:00
"""
Relay a privmsg to the event bus
"""
2017-09-18 19:56:22 -07:00
self.publish("privmsg", dumps([msg.args, msg.prefix[0], msg.trailing, {"prefix": msg.prefix}]))
@hook("JOIN")
2017-11-27 18:58:20 -08:00
def bus_join(self, msg, cmd):
2017-09-21 21:09:35 -07:00
"""
Relay a join message to the event bus
"""
2017-09-18 19:56:22 -07:00
self.publish("join", dumps([msg.prefix[0], msg.trailing, {"prefix": msg.prefix}]))
@hook("PART")
2017-11-27 18:58:20 -08:00
def bus_part(self, msg, cmd):
2017-09-21 21:09:35 -07:00
"""
Relay a part message to the event bus
"""
2017-09-18 19:56:22 -07:00
self.publish("part", dumps([msg.args, msg.prefix[0], msg.trailing, {"prefix": msg.prefix}]))
2017-09-18 20:12:08 -07:00
@hook("PRIVMSG")
2017-11-27 18:58:20 -08:00
def bus_command(self, msg, cmd):
2017-09-21 21:09:35 -07:00
"""
Parse commands and publish as separate channels on the bus. Commands like `.seen nick` will be published
to channel `command_seen`.
"""
2017-09-18 20:12:08 -07:00
match = COMMAND_RE.match(msg.trailing)
if match:
cmd_name = match.groups()[1]
cmd_args = msg.trailing[len(cmd_name) + 1:].strip()
self.publish("command_{}".format(cmd_name),
dumps([msg.args, msg.prefix[0], cmd_args, {"prefix": msg.prefix}]))
2017-09-18 19:56:22 -07:00
def onenable(self):
2017-09-21 21:09:35 -07:00
"""
Connect to the message bus when the module is enabled
"""
2017-09-18 19:56:22 -07:00
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):
2017-09-21 21:09:35 -07:00
"""
Disconnect to the message bus on shutdown
"""
2017-09-18 19:56:22 -07:00
self.log.warning("clean it up")
self.publish("sys", "offline")
self.bus.close()