Example #1
0
 def __init__(self):
     _settings, _ = import_settings()
     slack_api_token = _settings.get('SLACK_API_TOKEN', None)
     http_proxy = _settings.get('HTTP_PROXY', None)
     self.rtm_client = RTMClient(token=slack_api_token, proxy=http_proxy)
     self.web_client = WebClient(token=slack_api_token, proxy=http_proxy)
     self._bot_info = {}
     self._users = {}
     self._channels = {}
Example #2
0
    def __init__(self, bot_user_token, bot_id=None):
        self.name = BOT_NAME
        self.bot_id = bot_id
        if not self.bot_id:
            # Read the bot's id by calling auth.test
            response = WebClient(token=bot_user_token).api_call('auth.test')
            self.bot_id = response['user_id']
            logger.info(f"My bot_id is {self.bot_id}")

        self.sc = RTMClient(token=bot_user_token, run_async=True)

        # Connect our callback events to the RTM client
        RTMClient.run_on(event="hello")(self.on_hello)
        RTMClient.run_on(event="message")(self.on_message)
        RTMClient.run_on(event="goodbye")(self.on_goodbye)

        # Startup our client event loop
        self.future = self.sc.start()
        self.bot_start = dt.now()
        self.at_bot = f'<@{self.bot_id}>'
        logger.info("Created new SlackClient Instance")
Example #3
0
class LowLevelSlackClient(metaclass=Singleton):
    def __init__(self):
        _settings, _ = import_settings()
        slack_api_token = _settings.get('SLACK_API_TOKEN', None)
        http_proxy = _settings.get('HTTP_PROXY', None)
        self.rtm_client = RTMClient(token=slack_api_token, proxy=http_proxy)
        self.web_client = WebClient(token=slack_api_token, proxy=http_proxy)
        self._bot_info = {}
        self._users = {}
        self._channels = {}

    @staticmethod
    def get_instance() -> 'LowLevelSlackClient':
        return LowLevelSlackClient()

    def _register_user(self, user_response):
        user = User.from_api_response(user_response)
        self._users[user.id] = user
        return user

    def _register_channel(self, channel_response):
        channel = Channel.from_api_response(channel_response)
        self._channels[channel.id] = channel
        return channel

    def ping(self):
        # Ugly hack because some parts of slackclient > 2.0 are async-only (like the ping function)
        # and Slack Machine isn't async yet
        loop = asyncio.new_event_loop()
        result = self.rtm_client.ping()
        loop.run_until_complete(result)

    def _on_open(self, **payload):
        # Set bot info
        self._bot_info = payload['data']['self']
        # Build user cache
        all_users = call_paginated_endpoint(self.web_client.users_list,
                                            'members')
        for u in all_users:
            self._register_user(u)
        logger.debug("Number of users found: %s" % len(self._users))
        logger.debug("Users: %s" % ", ".join([
            f"{u.profile.display_name}|{u.profile.real_name}"
            for u in self._users.values()
        ]))
        # Build channel cache
        all_channels = call_paginated_endpoint(
            self.web_client.conversations_list,
            'channels',
            types='public_channel,private_channel')
        for c in all_channels:
            self._register_channel(c)
        logger.debug("Number of channels found: %s" % len(self._channels))
        logger.debug("Channels: %s" %
                     ", ".join([c.name for c in self._channels.values()]))

    def _on_team_join(self, **payload):
        user = self._register_user(payload['data']['user'])
        logger.debug("User joined team: %s" % user)

    def _on_user_change(self, **payload):
        user = self._register_user(payload['data']['user'])
        logger.debug("User changed: %s" % user)

    def _on_channel_created(self, **payload):
        channel_resp = self.web_client.channels_info(
            channel=payload['data']['channel']['id'])
        channel = self._register_channel(channel_resp['channel'])
        logger.debug("Channel created: %s" % channel)

    def _on_channel_updated(self, **payload):
        data = payload['data']
        if isinstance(data['channel'], dict):
            channel_id = data['channel']['id']
        else:
            channel_id = data['channel']
        channel_resp = self.web_client.channels_info(channel=channel_id)
        channel = self._register_channel(channel_resp['channel'])
        logger.debug("Channel updated: %s" % channel)

    def _on_channel_deleted(self, **payload):
        channel = self._channels[payload['data']['channel']]
        del self._channels[payload['data']['channel']]
        logger.debug("Channel %s deleted" % channel.name)

    @property
    def bot_info(self) -> Dict[str, str]:
        return self._bot_info

    def start(self):
        RTMClient.on(event='open', callback=self._on_open)
        RTMClient.on(event='team_join', callback=self._on_team_join)
        RTMClient.on(event='channel_created',
                     callback=self._on_channel_created)
        RTMClient.on(event='channel_deleted',
                     callback=self._on_channel_deleted)
        RTMClient.on(event='channel_rename', callback=self._on_channel_updated)
        RTMClient.on(event='channel_archive',
                     callback=self._on_channel_updated)
        RTMClient.on(event='channel_unarchive',
                     callback=self._on_channel_updated)
        RTMClient.on(event='user_change', callback=self._on_user_change)
        self.rtm_client.start()

    @property
    def users(self) -> Dict[str, User]:
        return self._users

    @property
    def channels(self) -> Dict[str, Channel]:
        return self._channels
Example #4
0
 def start(self):
     RTMClient.on(event='open', callback=self._on_open)
     RTMClient.on(event='team_join', callback=self._on_team_join)
     RTMClient.on(event='channel_created',
                  callback=self._on_channel_created)
     RTMClient.on(event='channel_deleted',
                  callback=self._on_channel_deleted)
     RTMClient.on(event='channel_rename', callback=self._on_channel_updated)
     RTMClient.on(event='channel_archive',
                  callback=self._on_channel_updated)
     RTMClient.on(event='channel_unarchive',
                  callback=self._on_channel_updated)
     RTMClient.on(event='user_change', callback=self._on_user_change)
     self.rtm_client.start()
Example #5
0
class SlackClient:
    def __init__(self, bot_user_token, bot_id=None):
        self.name = BOT_NAME
        self.bot_id = bot_id
        if not self.bot_id:
            # Read the bot's id by calling auth.test
            response = WebClient(token=bot_user_token).api_call('auth.test')
            self.bot_id = response['user_id']
            logger.info(f"My bot_id is {self.bot_id}")

        self.sc = RTMClient(token=bot_user_token, run_async=True)

        # Connect our callback events to the RTM client
        RTMClient.run_on(event="hello")(self.on_hello)
        RTMClient.run_on(event="message")(self.on_message)
        RTMClient.run_on(event="goodbye")(self.on_goodbye)

        # Startup our client event loop
        self.future = self.sc.start()
        self.bot_start = dt.now()
        self.at_bot = f'<@{self.bot_id}>'
        logger.info("Created new SlackClient Instance")

    def __repr__(self):
        return self.at_bot

    def __str__(self):
        return self.__repr__()

    def on_hello(self, **payload):
        """Slack is confirming our connection request"""
        logger.info(f"{self} is connected to Slack's RTM server")
        self.post_message(f"{self.name} is now online")

    # Callback Methods
    def on_message(self, **payload):
        """Slack has sent the bot a message"""
        data = payload["data"]
        if "text" in data and self.at_bot in data['text']:
            # parse everything after <@Bot> mention
            raw_cmd = data["text"].split(self.at_bot)[1].strip().lower()
            chan = data['channel']
            # handling cmd
            response = self.handle_command(raw_cmd, chan)
            self.post_message(response, chan)

    def handle_command(self, raw_cmd, chan):
        "Parses a raw_cmd string directed at the bot"
    #     return "To crush your enemies, to see them driven before you,"
    # + "and to hear the lamentations of their people!"
        response = None
        args = shlex.split(raw_cmd)
        cmd = args[0].lower()
        logger.info(f'{self} received command: "{raw_cmd}"')
        if cmd not in bot_commands:
            response = f'Unknown Command: "{cmd}"'
            logger.error(f'{self} {response}')
        # Now there is a valid command that must be processed
        elif cmd == 'help':
            response = "Available Commands:\n" + formatted_dict(bot_commands)
            logger.info(response)
        elif cmd == 'ping':
            response = f"{self.name} is active, current uptime:" + \
                f" {self.get_uptime()}"
            logger.info(response)
        elif cmd == 'list':
            pass
        elif cmd == 'exit' or cmd == 'quit':
            response = f"{self.name} Manual exit request at" + \
                f"{self.get_uptime()} uptime..."
            logger.warning(response)
            # The following is extremely hacky. DO NOT USE IN PRODUCTION!!!
            self.post_message(response)
            # Allow some time for sending the impending death message
            time.sleep(5.0)
            os.kill(os.getpid(), signal.SIGTERM)
        return response

    def on_goodbye(self, **payload):
        logger.warning(f"{self} is disconnecting now")

    def post_message(self, msg_text, channel=BOT_CHAN):
        """Sends a message to a Slack channel"""
        assert self.sc._web_client is not None
        if msg_text:
            self.sc._web_client.chat_postMessage(
                channel=channel,
                text=msg_text
            )

    def get_uptime(self):
        """Returns the duration for how long this client has been connected"""
        return dt.now() - self.bot_start

    # Waiting for something method
    def run(self):
        logger.info("Waiting for things to happen...")
        loop = self.future.get_loop()
        # Forever Waiting for a CTRL+C or a SIGTERM or SIGINT
        loop.run_until_complete(self.future)
        logger.info("Things are now done happening.")