Ejemplo n.º 1
0
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)
Ejemplo n.º 2
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):
        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)))
Ejemplo n.º 3
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):
        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)))
Ejemplo n.º 4
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):
        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)))
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
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)
Ejemplo n.º 7
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)
Ejemplo n.º 8
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)
Ejemplo n.º 9
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)))
Ejemplo n.º 10
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):
        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)))