class MessageDispatcher(object): def __init__(self, client, plugins): self._client = client self._pool = WorkerPool(self.dispatch_msg, settings.WORKERS_NUM) self._plugins = plugins self._channel_info = {} self.event = None def start(self): self._pool.start() @staticmethod def get_message(msg): return msg.get('data', {}).get('post', {}).get('message', '').strip() def ignore(self, _msg): msg = self.get_message(_msg) for prefix in settings.IGNORE_NOTIFIES: if msg.startswith(prefix): return True def is_mentioned(self, msg): mentions = msg.get('data', {}).get('mentions', []) return self._client.user['id'] in mentions def is_personal(self, msg): channel_id = msg['data']['post']['channel_id'] if channel_id in self._channel_info: channel_type = self._channel_info[channel_id] else: channel = self._client.api.channel(channel_id) channel_type = channel['channel']['type'] self._channel_info[channel_id] = channel_type return channel_type == 'D' def dispatch_msg(self, msg): category = msg[0] msg = msg[1] text = self.get_message(msg) responded = False msg['message_type'] = '?' if self.is_personal(msg): msg['message_type'] = 'D' for func, args in self._plugins.get_plugins(category, text): if func: responded = True try: func(Message(self._client, msg, self._pool), *args) except Exception as err: logger.exception(err) reply = '[%s] I have problem when handling "%s"\n' % ( func.__name__, text) reply += '```\n%s\n```' % traceback.format_exc() self._client.channel_msg( msg['data']['post']['channel_id'], reply) if not responded and category == 'respond_to': if settings.DEFAULT_REPLY_MODULE is not None: mod = importlib.import_module(settings.DEFAULT_REPLY_MODULE) if hasattr(mod, 'default_reply'): return getattr(mod, 'default_reply')(self, msg) self._default_reply(msg) def _on_new_message(self, msg): if self.ignore(msg) is True: return msg = self.filter_text(msg) if self.is_mentioned(msg) or self.is_personal(msg): self._pool.add_task(('respond_to', msg)) else: self._pool.add_task(('listen_to', msg)) def filter_text(self, msg): text = self.get_message(msg) if self.is_mentioned(msg): m = MESSAGE_MATCHER.match(text) if m: msg['data']['post']['message'] = m.group(2).strip() return msg def load_json(self): if self.event.get('data', {}).get('post'): self.event['data']['post'] = json.loads( self.event['data']['post']) if self.event.get('data', {}).get('mentions'): self.event['data']['mentions'] = json.loads( self.event['data']['mentions']) def loop(self): for self.event in self._client.messages(True, 'posted'): self.load_json() self._on_new_message(self.event) def _default_reply(self, msg): if settings.DEFAULT_REPLY: return self._client.channel_msg( msg['data']['post']['channel_id'], settings.DEFAULT_REPLY) default_reply = [ u'Bad command "%s", You can ask me one of the ' u'following questions:\n' % self.get_message(msg), ] docs_fmt = u'{1}' if settings.PLUGINS_ONLY_DOC_STRING else u'`{0}` {1}' default_reply += [ docs_fmt.format(p.pattern, v.__doc__ or "") for p, v in iteritems(self._plugins.commands['respond_to'])] self._client.channel_msg( msg['data']['post']['channel_id'], '\n'.join(default_reply))
class MessageDispatcher(object): def __init__(self, client, plugins): self._client = client self._pool = WorkerPool(self.dispatch_msg) self._plugins = plugins self._channel_info = {} def start(self): self._pool.start() @staticmethod def get_message(msg): return msg.get( 'props', {}).get('post', {}).get('message', '').strip() def is_mentioned(self, msg): mentions = msg.get('props', {}).get('mentions', []) return self._client.user['id'] in mentions def is_personal(self, msg): channel_id = msg['channel_id'] if channel_id in self._channel_info: channel_type = self._channel_info[channel_id] else: channel = self._client.api.channel(channel_id) channel_type = channel['channel']['type'] self._channel_info[channel_id] = channel_type return channel_type == 'D' def dispatch_msg(self, msg): category = msg[0] msg = msg[1] text = self.get_message(msg) responded = False msg['message_type'] = '?' if self.is_personal(msg): msg['message_type'] = 'D' for func, args in self._plugins.get_plugins(category, text): if func: responded = True try: func(Message(self._client, msg), *args) except Exception as err: logger.exception(err) reply = '[%s] I have problem when handling "%s"\n' % ( func.__name__, text) reply += '```\n%s\n```' % traceback.format_exc() self._client.channel_msg(msg['channel_id'], reply) if not responded and category == 'respond_to': self._default_reply(msg) def _on_new_message(self, msg): msg = self.filter_text(msg) if self.is_mentioned(msg) or self.is_personal(msg): self._pool.add_task(('respond_to', msg)) else: self._pool.add_task(('listen_to', msg)) def filter_text(self, msg): text = self.get_message(msg) if self.is_mentioned(msg): m = MESSAGE_MATCHER.match(text) if m: msg['props']['post']['message'] = m.group(2).strip() return msg def loop(self): for self.event in self._client.messages(True, 'posted'): self._on_new_message(self.event) def _default_reply(self, msg): default_reply = [ u'Bad command "%s", You can ask me one of the ' u'following questions:\n' % self.get_message(msg), ] docs_fmt = u'{1}' if settings.PLUGINS_ONLY_DOC_STRING else u'`{0}` {1}' default_reply += [ docs_fmt.format(p.pattern, v.__doc__ or "") for p, v in iteritems(self._plugins.commands['respond_to'])] self._client.channel_msg(msg['channel_id'], '\n'.join(default_reply))
class MessageDispatcher(object): def __init__(self, client, plugins): self._client = client self._pool = WorkerPool(self.dispatch_msg, settings.WORKERS_NUM) self._plugins = plugins self._channel_info = {} self.event = None def start(self): self._pool.start() @staticmethod def get_message(msg): return msg.get('data', {}).get('post', {}).get('message', '').strip() def ignore(self, _msg): msg = self.get_message(_msg) if any(item in msg for item in settings.IGNORE_NOTIFIES): return True def is_mentioned(self, msg): mentions = msg.get('data', {}).get('mentions', []) return self._client.user['id'] in mentions def is_personal(self, msg): try: channel_id = msg['data']['post']['channel_id'] if channel_id in self._channel_info: channel_type = self._channel_info[channel_id] else: channel = self._client.api.channel(channel_id) channel_type = channel['channel']['type'] self._channel_info[channel_id] = channel_type return channel_type == 'D' except KeyError as err: logger.info('Once time workpool exception caused by \ bot [added to/leave] [team/channel].') return False def dispatch_msg(self, msg): category = msg[0] msg = msg[1] text = self.get_message(msg) responded = False msg['message_type'] = '?' if self.is_personal(msg): msg['message_type'] = 'D' for func, args in self._plugins.get_plugins(category, text): if func: responded = True try: func(Message(self._client, msg, self._pool), *args) except Exception as err: logger.exception(err) reply = '[%s] I have problem when handling "%s"\n' % ( func.__name__, text) reply += '```\n%s\n```' % traceback.format_exc() self._client.channel_msg( msg['data']['post']['channel_id'], reply) if not responded and category == 'respond_to': if settings.DEFAULT_REPLY_MODULE is not None: mod = importlib.import_module(settings.DEFAULT_REPLY_MODULE) if hasattr(mod, 'default_reply'): return getattr(mod, 'default_reply')(self, msg) self._default_reply(msg) def _on_new_message(self, msg): if self.ignore(msg) is True: return msg = self.filter_text(msg) if self.is_mentioned(msg) or self.is_personal(msg): self._pool.add_task(('respond_to', msg)) else: self._pool.add_task(('listen_to', msg)) def filter_text(self, msg): text = self.get_message(msg) if self.is_mentioned(msg): m = MESSAGE_MATCHER.match(text) if m: msg['data']['post']['message'] = m.group(2).strip() return msg def load_json(self): if self.event.get('data', {}).get('post'): self.event['data']['post'] = json.loads( self.event['data']['post']) if self.event.get('data', {}).get('mentions'): self.event['data']['mentions'] = json.loads( self.event['data']['mentions']) def loop(self): for self.event in self._client.messages(True, ['posted', 'added_to_team', 'leave_team', \ 'user_added', 'user_removed']): if self.event: self.load_json() self._on_new_message(self.event) def _default_reply(self, msg): if settings.DEFAULT_REPLY: return self._client.channel_msg( msg['data']['post']['channel_id'], settings.DEFAULT_REPLY) default_reply = [ u'Bad command "%s", Here is what I currently know ' u'how to do:\n' % self.get_message(msg), ] # create dictionary organizing commands by plugin modules = {} for p, v in iteritems(self._plugins.commands['respond_to']): key = v.__module__.title().split('.')[1] if not key in modules: modules[key] = [] modules[key].append(v.__doc__) docs_fmt = u'\t{0}' if settings.PLUGINS_ONLY_DOC_STRING else u'\t - {0}' for module, commands in modules.items(): default_reply += [u'**Available Commands**'] # commands.sort(key=lambda x: x) for description in commands: if description: default_reply += [docs_fmt.format(description)] self._client.channel_msg( msg['data']['post']['channel_id'], '\n'.join(default_reply))