def __init__(self, slackclient, plugins, errors_to): self._client = slackclient self._pool = WorkerPool(self.dispatch_msg) self._plugins = plugins self._errors_to = None if errors_to: self._errors_to = self._client.find_channel_by_name(errors_to) if not self._errors_to: raise ValueError( 'Could not find errors_to recipient {!r}'.format( errors_to)) alias_regex = '' if getattr(settings, 'ALIASES', None): logger.info('using aliases %s', settings.ALIASES) alias_regex = '|(?P<alias>{})'.format('|'.join([re.escape(s) for s in settings.ALIASES.split(',')])) self.AT_MESSAGE_MATCHER = re.compile(r'^(?:\<@(?P<atuser>\w+)\>:?|(?P<username>\w+):{}) ?(?P<text>.*)$'.format(alias_regex))
class MessageDispatcher(object): def __init__(self, slackclient, plugins, errors_to): self._client = slackclient self._pool = WorkerPool(self.dispatch_msg) self._plugins = plugins self._errors_to = None self._running = True if errors_to: self._errors_to = self._client.find_channel_by_name(errors_to) if not self._errors_to: raise ValueError( 'Could not find errors_to recipient {!r}'.format( errors_to)) alias_regex = '' if getattr(settings, 'ALIASES', None): logger.info('using aliases %s', settings.ALIASES) alias_regex = '|(?P<alias>{})'.format('|'.join( [re.escape(s) for s in settings.ALIASES.split(',')])) self.AT_MESSAGE_MATCHER = re.compile( r'^(?:\<@(?P<atuser>\w+)\>:?|(?P<username>\w+):{}) ?(?P<text>.*)$'. format(alias_regex)) def start(self): self._pool.start() def dispatch_msg(self, msg): category = msg[0] msg = msg[1] if not self._dispatch_msg_handler(category, msg): if category == u'respond_to': if not self._dispatch_msg_handler('default_reply', msg): self._default_reply(msg) def _dispatch_msg_handler(self, category, msg): responded = False for func, args in self._plugins.get_plugins(category, msg['text']): if func: responded = True try: func(Message(self._client, msg), *args) except: logger.exception( 'failed to handle message %s with plugin "%s"', msg['text'], func.__name__) reply = u'[{}] I had a problem handling "{}"\n'.format( func.__name__, msg['text']) tb = u'```\n{}\n```'.format(traceback.format_exc()) self._client.rtm_send_message(msg['channel'], reply) if self._errors_to: self._client.rtm_send_message( self._errors_to, '{}\n{}'.format(reply, tb)) self._running = False return responded def _on_new_message(self, msg): # ignore edits subtype = msg.get('subtype', '') if subtype == u'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 == u'slackbot': 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 _get_bot_id(self): return self._client.login_data['self']['id'] def _get_bot_name(self): return self._client.login_data['self']['name'] def filter_text(self, msg): full_text = msg.get('text', '') channel = msg['channel'] bot_name = self._get_bot_name() bot_id = self._get_bot_id() m = self.AT_MESSAGE_MATCHER.match(full_text) if channel[0] == 'C' or channel[0] == 'G': if not m: return matches = m.groupdict() atuser = matches.get('atuser') username = matches.get('username') text = matches.get('text') alias = matches.get('alias') if alias: atuser = bot_id if atuser != bot_id and username != bot_name: # a channel message at other user return logger.debug('got an AT message: %s', text) msg['text'] = text else: if m: msg['text'] = m.groupdict().get('text', None) return msg def loop(self): while self._running: 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 = settings.DEFAULT_REPLY if default_reply is None: default_reply = [ u'Bad command "{}", You can ask me one of the following ' u'questions:\n' % msg['text'] ] default_reply += [ u' • `{0}` {1}'.format(p.pattern, v.__doc__ or "") for p, v in six.iteritems(self._plugins.commands['respond_to']) ] # pylint: disable=redefined-variable-type default_reply = u'\n'.join(default_reply) m = Message(self._client, msg) m.reply(default_reply)
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: if 'username' in msg: username = msg['username'] else: return if username == botname or username == 'slackbot': 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' • `{}`'.format(p.pattern) for p in self._plugins.commands['respond_to'].iterkeys()] self._client.rtm_send_message(msg['channel'], '\n'.join(to_utf8(default_reply)))
def __init__(self, slackclient, plugins): self._client = slackclient self._pool = WorkerPool(self.slack_msg_dispatcher) 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 == 'slackbot': 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)))
class MessageDispatcher(object): def __init__(self, slackclient, plugins, errors_to): self._client = slackclient self._pool = WorkerPool(self.dispatch_msg) self._plugins = plugins self._errors_to = None self._delayed_messages = {} if errors_to: self._errors_to = self._client.find_channel_by_name(errors_to) if not self._errors_to: raise ValueError( 'Could not find errors_to recipient {!r}'.format( errors_to)) alias_regex = '' if getattr(settings, 'ALIASES', None): logger.info('using aliases %s', settings.ALIASES) alias_regex = '|(?P<alias>{})'.format('|'.join([re.escape(s) for s in settings.ALIASES.split(',')])) self.AT_MESSAGE_MATCHER = re.compile(r'^(?:\<@(?P<atuser>\w+)\>:?|(?P<username>\w+):{}) ?(?P<text>.*)$'.format(alias_regex)) def start(self): self._pool.start() def delayed_message(self, key, message, text, delay): run_time = (datetime.now() + timedelta(0, delay)) self._delayed_messages[key] = {'run_time': run_time, 'message': message, 'text': text } def cancel_delayed_message(self, key): del self._delayed_messages[key] def append_delayed_message(self, key, append_text): self._delayed_messages[key]['text'] += append_text def dispatch_msg(self, msg): category = msg[0] msg = msg[1] if not self._dispatch_msg_handler(category, msg): if category == u'respond_to': if not self._dispatch_msg_handler('default_reply', msg): self._default_reply(msg) def _dispatch_msg_handler(self, category, msg): responded = False for func, args in self._plugins.get_plugins(category, msg['text']): if func: responded = True try: func(Message(self._client, msg), *args) except: logger.exception( 'failed to handle message %s with plugin "%s"', msg['text'], func.__name__) reply = u'[{}] I had a problem handling "{}"\n'.format( func.__name__, msg['text']) tb = u'```\n{}\n```'.format(traceback.format_exc()) if self._errors_to: self._client.rtm_send_message(msg['channel'], reply) self._client.rtm_send_message(self._errors_to, '{}\n{}'.format(reply, tb)) else: self._client.rtm_send_message(msg['channel'], '{}\n{}'.format(reply, tb)) return responded def _on_new_message(self, msg): # ignore edits subtype = msg.get('subtype', '') if subtype == u'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 == u'slackbot': 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 _get_bot_id(self): return self._client.login_data['self']['id'] def _get_bot_name(self): return self._client.login_data['self']['name'] def filter_text(self, msg): full_text = msg.get('text', '') channel = msg['channel'] bot_name = self._get_bot_name() bot_id = self._get_bot_id() m = self.AT_MESSAGE_MATCHER.match(full_text) if channel[0] == 'C' or channel[0] == 'G': if not m: return matches = m.groupdict() atuser = matches.get('atuser') username = matches.get('username') text = matches.get('text') alias = matches.get('alias') if alias: atuser = bot_id if atuser != bot_id and username != bot_name: # a channel message at other user return logger.debug('got an AT message: %s', text) msg['text'] = text else: if m: msg['text'] = m.groupdict().get('text', None) 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) now = datetime.now() sent = [] for k, message in self._delayed_messages.items(): if(now > message['run_time']): sent.append(k) message['message'].reply(message['text']) for s in sent: del self._delayed_messages[s] time.sleep(1) def _default_reply(self, msg): default_reply = settings.DEFAULT_REPLY if default_reply is None: default_reply = [ u'Bad command "{}", You can ask me one of the following ' u'questions:\n'.format( msg['text']), ] default_reply += [ u' • `{0}` {1}'.format(p.pattern, v.__doc__ or "") for p, v in six.iteritems(self._plugins.commands['respond_to'])] # pylint: disable=redefined-variable-type default_reply = u'\n'.join(default_reply) m = Message(self._client, msg) m.reply(default_reply)
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 global USERNAME 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'] print (username) print (msg['channel']) except KeyError: if 'username' in msg: username = msg['username'] else: return if username == botname or username == 'slackbot': return if username not in USERNAME: if msg['channel']=="G0L8HPGA3": USERNAME.append(username) else: self._not_in_username_reply(username,msg) 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 _not_in_username_reply(self,username,msg): msg_reply = [ u'`I am sorry "%s", I am not permitted to talk with you`' %username ] self._client.rtm_send_message(msg['channel'],'\n'.join(to_utf8(msg_reply))) def _default_reply(self, msg): default_reply = [ u'`Unrecognized command "%s", Type Help for Help`' % msg['text'] ] self._client.rtm_send_message(msg['channel'], '\n'.join(to_utf8(default_reply)))
class MessageDispatcher(object): def __init__(self, slackclient, plugins, errors_to): self._client = slackclient self._pool = WorkerPool(self.dispatch_msg) self._plugins = plugins self._errors_to = None if errors_to: self._errors_to = self._client.find_channel_by_name(errors_to) if not self._errors_to: raise ValueError( 'Could not find errors_to recipient {!r}'.format( errors_to)) alias_regex = '' if getattr(settings, 'ALIASES', None): logger.info('using aliases %s', settings.ALIASES) alias_regex = '|(?P<alias>{})'.format('|'.join( [re.escape(s) for s in settings.ALIASES.split(',')])) self.AT_MESSAGE_MATCHER = re.compile( r'^(?:\<@(?P<atuser>\w+)\>:?|(?P<username>\w+):{}) ?(?P<text>[\s\S]*)$' .format(alias_regex)) def start(self): self._pool.start() def dispatch_msg(self, msg): category = msg[0] msg = msg[1] if not self._dispatch_msg_handler(category, msg): if category == u'respond_to': if not self._dispatch_msg_handler('default_reply', msg): self._default_reply(msg) def _dispatch_msg_handler(self, category, msg): responded = False for func, args in self._plugins.get_plugins(category, msg.get('text', None)): if func: responded = True try: func(Message(self._client, msg), *args) except: logger.exception( 'failed to handle message %s with plugin "%s"', msg['text'], func.__name__) reply = u'[{}] I had a problem handling "{}" (cc: <@ULTPW7YAC>)\n'.format( func.__name__, msg['text']) tb = u'```\n{}\n```'.format(traceback.format_exc()) if self._errors_to: self._client.rtm_send_message(msg['channel'], reply, parse="full") self._client.rtm_send_message( self._errors_to, '{}\n{}'.format(reply, tb)) else: self._client.rtm_send_message( msg['channel'], '{}\n{}'.format(reply, tb)) return responded def _on_new_message(self, msg): # ignore edits subtype = msg.get('subtype', '') if subtype == u'message_changed': return botname = self._get_bot_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 == u'slackbot': 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 _get_bot_id(self): return self._client.login_data['self']['id'] def _get_bot_name(self): return self._client.login_data['self']['name'] def filter_text(self, msg): full_text = msg.get('text', '') or '' channel = msg['channel'] bot_name = self._get_bot_name() bot_id = self._get_bot_id() m = self.AT_MESSAGE_MATCHER.match(full_text) if channel[0] == 'C' or channel[0] == 'G': if not m: return matches = m.groupdict() atuser = matches.get('atuser') username = matches.get('username') text = matches.get('text') alias = matches.get('alias') if alias: atuser = bot_id if atuser != bot_id and username != bot_name: # a channel message at other user return logger.debug('got an AT message: %s', text) msg['text'] = text else: if m: msg['text'] = m.groupdict().get('text', None) return msg def loop(self): """ Main loop function for all the repeated functionalities of Fido """ from slackbot.plugins import piazza_pager from slackbot.plugins import react_check while True: events = self._client.rtm_read() for event in events: event_type = event.get('type') if event_type == 'message': self._on_new_message(event) elif event_type in [ 'channel_created', 'channel_rename', 'group_joined', 'group_rename', 'im_created' ]: channel = [event['channel']] self._client.parse_channel_data(channel) elif event_type in ['team_join', 'user_change']: user = [event['user']] self._client.parse_user_data(user) now = datetime.now(tz=pytz.utc).astimezone(timezone('US/Pacific')) whitened_now = now.replace(second=0, microsecond=0, tzinfo=None) curr_time = now.strftime("%H:%M:%S") if curr_time in settings.PIAZZA_PAGER_REFRESH_TOD: piazza_pager.check_for_new_posts() if whitened_now in react_check.end_ts_to_message_infos: react_check.check_for_reacts(whitened_now) time.sleep(1) # Refresh every 1 second def _default_reply(self, msg): default_reply = settings.DEFAULT_REPLY if default_reply is None: default_reply = [ u'Bad command "{}", You can ask me one of the following ' u'questions:\n'.format(msg['text']), ] default_reply += [ u' • `{0}` {1}'.format(p.pattern, v.__doc__ or "") for p, v in six.iteritems(self._plugins.commands['respond_to']) ] # pylint: disable=redefined-variable-type default_reply = u'\n'.join(default_reply) m = Message(self._client, msg) m.reply(default_reply, in_thread=True)
def __init__(self, slackclient, plugins): self._client = slackclient self._pool = WorkerPool(self.dispatch_msg) self._plugins = plugins self._stop = threading.Event()
class MessageDispatcher(object): def __init__(self, slackclient, plugins): self._client = slackclient self._pool = WorkerPool(self.dispatch_msg) self._plugins = plugins self._stop = threading.Event() def start(self): self._pool.start() def dispatch_msg(self, msg): category = msg[0] msg = msg[1] text = self.get_text(msg) logger.info("Trying plugins on message %s" % text) responded = False for func, args in self._plugins.get_plugins(category, text): if func: responded = True try: logger.info("Calling plugin '%s'" % func.__name__) func(Message(self._client, msg), *args) except: err = 'Failed to handle message %s with plugin "%s"' logger.exception(err, text, func.__name__) #logger.exception('\n%s\n' % traceback.format_exc()) reply = 'YIPE! "%s" failed to handle "%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): """ Handle a new message and dispatch to the appropriate pool. If the message came from a bot, use the appropriate service handler. """ logger.info("Received message: %s" % msg) # ignore edits ignore = ['message_changed', 'channel_join', 'message_deleted'] subtype = msg.get('subtype', '') if subtype in ignore: return botname = self._client.login_data['self']['name'] if self.get_username(msg) == botname: return if from_bot(msg): return self._on_bot_message(msg) 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 _on_bot_message(self, msg): """ Check bot handlers for appropriate handler, otherwise return. """ bot_id = msg['bot_id'] if bot_id not in settings.HANDLERS: err = "Ignoring message from bot_id %s with no registered handler" logger.info(err % bot_id) return def _get_handler(bot_id): val = settings.HANDLERS[bot_id] if not isinstance(val, tuple): return (val, []) return (val[0], val[1:]) (handler, args) = _get_handler(bot_id) module = importlib.import_module(handler) #import pdb;pdb.set_trace() if not hasattr(module, 'handle_bot_message'): err = "Bot handler for %s does not have a handle_bot_msg function" logger.warning(err % bot_id) return handler_fn = getattr(module, 'handle_bot_message') try: handler_fn(Message(self._client, msg), *args) except: err = 'Failed to handle message %s with bot handler "%s"' logger.exception(err, msg, handler) #logger.exception('\n%s\n' % traceback.format_exc()) def get_username(self, msg): try: #import pdb;pdb.set_trace() if from_bot(msg): username = msg['bot_id'] else: msguser = self._client.users.get(msg['user']) username = msguser['name'] except: if 'username' in msg: username = msg['username'] elif 'user' in msg: username = msg['user'] else: username = '******' err = 'Failed to get username for %s' logger.exception(err, username) msg['username'] = username return username def get_text(self, msg): """Get text from message. If main text is empty, look for text field in attachments. """ text = msg.get('text', '') if text == '' and 'attachments' in msg: try: text = msg['attachments'][0]['text'] except: text = '' return text def filter_text(self, msg): text = self.get_text(msg) logger.info("Got text: %s" % 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 not self._stop.isSet(): try: events = self._client.rtm_read() except slacker.Error, e: self.stop() break for event in events: if event.get('type') != 'message': continue self._on_new_message(event) self._stop.wait(1.0)
class MessageDispatcher(object): def __init__(self, slackclient, plugins): self._client = slackclient self._pool = WorkerPool(self.dispatch_msg) self._plugins = plugins self._stop = threading.Event() def start(self): self._pool.start() def dispatch_msg(self, msg): category = msg[0] msg = msg[1] text = self.get_text(msg) logger.info("Trying plugins on message %s" % text) responded = False for func, args in self._plugins.get_plugins(category, text): if func: responded = True try: logger.info("Calling plugin '%s'" % func.__name__) func(Message(self._client, msg), *args) except: err = 'Failed to handle message %s with plugin "%s"' logger.exception(err, text, func.__name__) #logger.exception('\n%s\n' % traceback.format_exc()) reply = 'YIPE! "%s" failed to handle "%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): """ Handle a new message and dispatch to the appropriate pool. If the message came from a bot, use the appropriate service handler. """ logger.info("Received message: %s"%msg) # ignore edits ignore = [ 'message_changed', 'channel_join', 'message_deleted' ] subtype = msg.get('subtype', '') if subtype in ignore: return botname = self._client.login_data['self']['name'] if self.get_username(msg) == botname: return if from_bot(msg): return self._on_bot_message(msg) 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 _on_bot_message(self, msg): """ Check bot handlers for appropriate handler, otherwise return. """ bot_id = msg['bot_id'] if bot_id not in settings.HANDLERS: err = "Ignoring message from bot_id %s with no registered handler" logger.info(err % bot_id) return def _get_handler(bot_id): val = settings.HANDLERS[bot_id] if not isinstance(val,tuple): return (val,[]) return (val[0], val[1:]) (handler,args) = _get_handler(bot_id) module = importlib.import_module(handler) #import pdb;pdb.set_trace() if not hasattr(module, 'handle_bot_message'): err = "Bot handler for %s does not have a handle_bot_msg function" logger.warning(err % bot_id) return handler_fn = getattr(module, 'handle_bot_message') try: handler_fn(Message(self._client, msg), *args) except: err = 'Failed to handle message %s with bot handler "%s"' logger.exception(err, msg, handler) #logger.exception('\n%s\n' % traceback.format_exc()) def get_username(self, msg): try: #import pdb;pdb.set_trace() if from_bot(msg): username = msg['bot_id'] else: msguser = self._client.users.get(msg['user']) username = msguser['name'] except: if 'username' in msg: username = msg['username'] elif 'user' in msg: username = msg['user'] else: username = '******' err = 'Failed to get username for %s' logger.exception(err, username) msg['username'] = username return username def get_text(self, msg): """Get text from message. If main text is empty, look for text field in attachments. """ text = msg.get('text', '') if text == '' and 'attachments' in msg: try: text = msg['attachments'][0]['text'] except: text = '' return text def filter_text(self, msg): text = self.get_text(msg) logger.info("Got text: %s" % 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 not self._stop.isSet(): try: events = self._client.rtm_read() except slacker.Error, e: self.stop() break for event in events: if event.get('type') != 'message': continue self._on_new_message(event) self._stop.wait(1.0)
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): text = msg['text'] func, args = self._plugins.get_plugin(text) if not func: self._default_reply(msg) else: 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) return 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: if 'username' in msg: username = msg['username'] else: return if username == botname or username == 'slackbot': return msg = self.filter_text(msg) if msg: self._pool.add_task(msg) def filter_text(self, msg): text = msg.get('text', '') channel = msg['channel'] if channel[0] == 'C': 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.groups(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 questsion:\n' % msg['text'], ] default_reply += [ u' • %s' % str(f.__name__) for f in self._plugins.commands.itervalues() ] self._client.rtm_send_message(msg['channel'], '\n'.join(to_utf8(default_reply)))
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 global USERNAME 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'] print(username) print(msg['channel']) except KeyError: if 'username' in msg: username = msg['username'] else: return if username == botname or username == 'slackbot': return if username not in USERNAME: if msg['channel'] == "G0L8HPGA3": USERNAME.append(username) else: self._not_in_username_reply(username, msg) 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 _not_in_username_reply(self, username, msg): msg_reply = [ u'`I am sorry "%s", I am not permitted to talk with you`' % username ] self._client.rtm_send_message(msg['channel'], '\n'.join(to_utf8(msg_reply))) def _default_reply(self, msg): default_reply = [ u'`Unrecognized command "%s", Type Help for Help`' % msg['text'] ] self._client.rtm_send_message(msg['channel'], '\n'.join(to_utf8(default_reply)))