def __init__(self, slackclient, plugins): self._client = slackclient self._pool = WorkerPool(self.dispatch_msg) self._plugins = plugins
class MessageDispatcher(object): def __init__(self, slackclient, plugins): self._client = slackclient self._pool = WorkerPool(self.dispatch_msg) self._plugins = plugins def start(self): self._pool.start() def dispatch_msg(self, msg): category = msg[0] msg = msg[1] text = msg['text'] responded = False for func, args in self._plugins.get_plugins(category, text): if func: responded = True try: func(Message(self._client, msg), *args) except: logger.exception('failed to handle message %s with plugin "%s"', text, func.__name__) reply = '[%s] I have problem when handling "%s"\n' % (func.__name__, text) reply += '```\n%s\n```' % traceback.format_exc() self._client.rtm_send_message(msg['channel'], reply) if not responded and category == 'respond_to': self._default_reply(msg) def _on_new_message(self, msg): # ignore edits subtype = msg.get('subtype', '') if subtype == 'message_changed': return botname = self._client.login_data['self']['name'] try: msguser = self._client.users.get(msg['user']) username = msguser['name'] except (KeyError, TypeError): if 'username' in msg: username = msg['username'] else: return if username == botname or username == 'pybot': return msg_respond_to = self.filter_text(msg) if msg_respond_to: self._pool.add_task(('respond_to', msg_respond_to)) else: self._pool.add_task(('listen_to', msg)) def filter_text(self, msg): text = msg.get('text', '') channel = msg['channel'] if channel[0] == 'C' or channel[0] == 'G': m = AT_MESSAGE_MATCHER.match(text) if not m: return atuser, text = m.groups() if atuser != self._client.login_data['self']['id']: # a channel message at other user return logger.debug('got an AT message: %s', text) msg['text'] = text else: m = AT_MESSAGE_MATCHER.match(text) if m: msg['text'] = m.group(2) return msg def loop(self): while True: events = self._client.rtm_read() for event in events: if event.get('type') != 'message': continue self._on_new_message(event) time.sleep(1) def _default_reply(self, msg): default_reply = [ u'Bad command "%s", You can ask me one of the following questions:\n' % msg['text'], ] default_reply += [u' • `{0}` {1}'.format(p.pattern, v.__doc__ or "") for p, v in iteritems(self._plugins.commands['respond_to'])] self._client.rtm_send_message(msg['channel'], '\n'.join(to_utf8(default_reply)))