Example #1
0
def handle_slack_context():
    try:
        rtm_client = RTMClient(token=token)
        logger.info("Opening connection to slack.")
        rtm_client.start()
    except SlackApiError:
        logger.exception("Error establishing connection to slack.")
Example #2
0
async def run_client(loop, **kwargs):
    """Run slack RTM server."""
    logging.info("starting client")
    slack_token = config.get('TOKEN')
    rtm_client = RTMClient(token=slack_token, loop=loop, run_async=True)
    rtm_client.start()
    logging.info("started client server")
    return
    async def test_issue_611(self):
        channel_id = os.environ[SLACK_SDK_TEST_RTM_TEST_CHANNEL_ID]
        text = "This message was sent by <https://slack.dev/python-slackclient/|python-slackclient>! (test_issue_611)"

        self.message_count, self.reaction_count = 0, 0

        async def process_messages(**payload):
            self.logger.info(payload)
            if ("subtype" in payload["data"]
                    and payload["data"]["subtype"] == "message_replied"):
                return  # skip

            self.message_count += 1
            raise Exception("something is wrong!"
                            )  # This causes the termination of the process

        async def process_reactions(**payload):
            self.logger.info(payload)
            self.reaction_count += 1

        rtm = RTMClient(token=self.bot_token, run_async=True)
        RTMClient.on(event="message", callback=process_messages)
        RTMClient.on(event="reaction_added", callback=process_reactions)

        web_client = WebClient(token=self.bot_token, run_async=True)
        message = await web_client.chat_postMessage(channel=channel_id,
                                                    text=text)
        ts = message["ts"]

        await asyncio.sleep(3)

        # intentionally not waiting here
        rtm.start()

        try:
            await asyncio.sleep(3)

            first_reaction = await web_client.reactions_add(channel=channel_id,
                                                            timestamp=ts,
                                                            name="eyes")
            self.assertFalse("error" in first_reaction)
            await asyncio.sleep(2)

            should_be_ignored = await web_client.chat_postMessage(
                channel=channel_id, text="Hello?", thread_ts=ts)
            self.assertFalse("error" in should_be_ignored)
            await asyncio.sleep(2)

            second_reaction = await web_client.reactions_add(
                channel=channel_id, timestamp=ts, name="tada")
            self.assertFalse("error" in second_reaction)
            await asyncio.sleep(2)

            self.assertEqual(self.message_count, 1)
            self.assertEqual(self.reaction_count, 2)
        finally:
            if not rtm._stopped:
                rtm.stop()
Example #4
0
def run():
    try:
        rtm_client = RTMClient(token=os.getenv("SLACK_TOKEN"))
        rtm_client.start()
    except ClientConnectorError as e:
        logger.error("Possibly no internet connection available")
        logger.error(str(e))
        time.sleep(5 * 60)
        exit(1)
Example #5
0
def main():
    ssl_context = ssl_lib.create_default_context(cafile=certifi.where())
    # Real-time messaging client with Slack
    global rtm_client
    rtm_client = RTMClient(token=SLACK_TOKEN, ssl=ssl_context)
    try:
        print("[SUCCESS] Your bot is running!")
        rtm_client.start()
    except:
        print("[ERROR] Your bot is not running.")
Example #6
0
    async def test_issue_558(self):
        channel_id = os.environ[SLACK_SDK_TEST_RTM_TEST_CHANNEL_ID]
        text = "This message was sent by <https://slack.dev/python-slackclient/|python-slackclient>! (test_issue_558)"

        self.message_count, self.reaction_count = 0, 0

        async def process_messages(**payload):
            self.logger.debug(payload)
            self.message_count += 1
            await asyncio.sleep(10)  # this used to block all other handlers

        async def process_reactions(**payload):
            self.logger.debug(payload)
            self.reaction_count += 1

        rtm = RTMClient(token=self.bot_token, run_async=True)
        RTMClient.on(event="message", callback=process_messages)
        RTMClient.on(event="reaction_added", callback=process_reactions)

        web_client = WebClient(token=self.bot_token, run_async=True)
        message = await web_client.chat_postMessage(channel=channel_id,
                                                    text=text)
        self.assertFalse("error" in message)
        ts = message["ts"]
        await asyncio.sleep(3)

        # intentionally not waiting here
        rtm.start()
        await asyncio.sleep(3)

        try:
            first_reaction = await web_client.reactions_add(channel=channel_id,
                                                            timestamp=ts,
                                                            name="eyes")
            self.assertFalse("error" in first_reaction)
            await asyncio.sleep(2)

            message = await web_client.chat_postMessage(channel=channel_id,
                                                        text=text)
            self.assertFalse("error" in message)
            # used to start blocking here

            # This reaction_add event won't be handled due to a bug
            second_reaction = await web_client.reactions_add(
                channel=channel_id, timestamp=ts, name="tada")
            self.assertFalse("error" in second_reaction)
            await asyncio.sleep(2)

            self.assertEqual(self.message_count, 1)
            self.assertEqual(self.reaction_count, 2)  # used to fail
        finally:
            if not rtm._stopped:
                rtm.stop()
Example #7
0
class TestRTMClient(unittest.TestCase):
    """Runs integration tests with real Slack API

    https://github.com/slackapi/python-slack-sdk/issues/605
    """
    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.bot_token = os.environ[SLACK_SDK_TEST_CLASSIC_APP_BOT_TOKEN]
        self.channel_id = os.environ[SLACK_SDK_TEST_RTM_TEST_CHANNEL_ID]
        self.rtm_client = RTMClient(token=self.bot_token, run_async=False)

    def tearDown(self):
        # Reset the decorators by @RTMClient.run_on
        RTMClient._callbacks = collections.defaultdict(list)

    @pytest.mark.skipif(condition=is_not_specified(),
                        reason="To avoid rate_limited errors")
    def test_issue_605(self):
        self.text = "This message was sent to verify issue #605"
        self.called = False

        @RTMClient.run_on(event="message")
        def process_messages(**payload):
            self.logger.info(payload)
            self.called = True

        def connect():
            self.logger.debug("Starting RTM Client...")
            self.rtm_client.start()

        t = threading.Thread(target=connect)
        t.daemon = True
        try:
            t.start()
            self.assertFalse(self.called)

            time.sleep(3)

            self.web_client = WebClient(
                token=self.bot_token,
                run_async=False,
            )
            new_message = self.web_client.chat_postMessage(
                channel=self.channel_id, text=self.text)
            self.assertFalse("error" in new_message)

            time.sleep(5)
            self.assertTrue(self.called)
        finally:
            t.join(0.3)
 def test_issue_530(self):
     try:
         rtm_client = RTMClient(
             token="I am not a token", run_async=False, loop=asyncio.new_event_loop()
         )
         rtm_client.start()
         self.fail("Raising an error here was expected")
     except Exception as e:
         self.assertEqual(
             "The request to the Slack API failed.\n"
             "The server responded with: {'ok': False, 'error': 'invalid_auth'}",
             str(e),
         )
     finally:
         if not rtm_client._stopped:
             rtm_client.stop()
Example #9
0
async def slack_client_and_sleeps():
    # real-time-messaging Slack client
    client = RTMClient(token=token, run_async=True)

    sleepy_count_task = asyncio.create_task(sleepy_count("first counter", 1))
    sleepy_count_task2 = asyncio.create_task(sleepy_count("second counter", 3))

    await asyncio.gather(client.start(), sleepy_count_task, sleepy_count_task2)
Example #10
0
class Bellchan:

    def __init__(self):
        setup_logger()

        self.settings = Settings
        self.rtm_client = RTMClient(token=self.settings.SLACK_API_TOKEN)
        self.web_client = LegacyWebClient(token=self.settings.SLACK_API_TOKEN)

        self.schedule = schedule
        for func in self.scheduled_plugins:
            func(self, self.schedule, self.handle_schedule_error)

            logger.info(f'Set schedule function [{func.__name__}]')

    @property
    def scheduled_plugins(self):
        return scheduled_plugins.__all__

    def push_message(self, text: str, with_channel: bool = False) -> None:
        if with_channel:
            text = f'<!channel> {text}'

        self.web_client.chat_postMessage(
            username=Settings.BOT_NAME,
            icon_url=Settings.BOT_ICON_URL,
            channel=Settings.DEFAULT_CHANNEL_ID,
            text=text,
        )

    def handle_schedule_error(self):
        def receive_func(func):
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    handle_error(self.web_client, Settings.DEFAULT_CHANNEL_ID, e)
            return wrapper
        return receive_func

    def run(self):
        Process(target=run_schedule, args=(self,)).start()

        self.rtm_client.start()
Example #11
0
async def slack_client():
    # real-time-messaging Slack client
    client = RTMClient(token=token, run_async=True)

    await asyncio.gather(client.start())
Example #12
0
openRes = client.conversations_open(users=userIds)
# openRes = client.conversations_open(users=['U01K53KBBEC', 'U01KAV74U57'])
# print(openRes)

# send message in the app's channel
# response = client.api_call(
#     api_method='chat.postMessage',
#     json={'channel': openRes["channel"]["id"],
#           "text": "Tets for sending message to both Beena and Sachin."}
# )
# print(response)

# send message each users separately
for userId in userIds:
    response = client.api_call(api_method='chat.postMessage',
                               json={
                                   'channel': userId,
                                   "text": "Tets for sending message."
                               })

# send message as slackbot
# response = client.api_call(
#     api_method='chat.postMessage',
#     json={'channel': userId, "text": "Hi Beena, This is a test."}
# )
# print(response)

rtm_client = RTMClient(token=slack_token)
rtm_client.start()
print("END")
Example #13
0
# When a user sends a DM, the event type will be 'message'.
# Here we'll link the message callback to the 'message' event.
@RTMClient.run_on(event="message")
async def message(**payload):
    """Display the onboarding welcome message after receiving a message
    that contains "start".
    """
    data = payload["data"]
    web_client = payload["web_client"]
    channel_id = data.get("channel")
    user_id = data.get("user")
    text = data.get("text")

    if text and text.lower() == "start":
        return await start_onboarding(web_client, user_id, channel_id)


if __name__ == "__main__":
    logger = logging.getLogger()
    logger.setLevel(logging.DEBUG)
    logger.addHandler(logging.StreamHandler())
    ssl_context = ssl_lib.create_default_context(cafile=certifi.where())
    slack_token = os.environ["SLACK_BOT_TOKEN"]
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    rtm_client = RTMClient(token=slack_token,
                           ssl=ssl_context,
                           run_async=True,
                           loop=loop)
    loop.run_until_complete(rtm_client.start())
class TestRTMClient(unittest.TestCase):
    """Runs integration tests with real Slack API

    https://github.com/slackapi/python-slack-sdk/issues/569
    """
    def setUp(self):
        if not hasattr(self, "logger"):
            self.logger = logging.getLogger(__name__)
            self.channel_id = os.environ[SLACK_SDK_TEST_RTM_TEST_CHANNEL_ID]
            self.bot_token = os.environ[SLACK_SDK_TEST_CLASSIC_APP_BOT_TOKEN]

        if not hasattr(
                self,
                "cpu_monitor") or not TestRTMClient.cpu_monitor.is_alive():

            def run_cpu_monitor(self):
                self.logger.debug("Starting CPU monitor in another thread...")
                TestRTMClient.cpu_usage = 0
                while True:
                    p = psutil.Process(os.getpid())
                    current_cpu_usage: float = p.cpu_percent(interval=0.5)
                    self.logger.debug(current_cpu_usage)
                    if current_cpu_usage > TestRTMClient.cpu_usage:
                        TestRTMClient.cpu_usage = current_cpu_usage

            TestRTMClient.cpu_monitor = threading.Thread(
                target=run_cpu_monitor, args=[self])
            TestRTMClient.cpu_monitor.daemon = True
            TestRTMClient.cpu_monitor.start()

        self.rtm_client = None
        self.web_client = None

    def tearDown(self):
        # Reset the decorators by @RTMClient.run_on
        RTMClient._callbacks = collections.defaultdict(list)
        # Stop the Client
        if hasattr(self, "rtm_client") and not self.rtm_client._stopped:
            self.rtm_client.stop()

    @pytest.mark.skipif(condition=is_not_specified(),
                        reason="To avoid rate_limited errors")
    def test_cpu_usage(self):
        self.rtm_client = RTMClient(token=self.bot_token,
                                    run_async=False,
                                    loop=asyncio.new_event_loop())
        self.web_client = WebClient(token=self.bot_token)

        self.call_count = 0
        TestRTMClient.cpu_usage = 0

        @RTMClient.run_on(event="message")
        def send_reply(**payload):
            self.logger.debug(payload)
            event = payload["data"]
            if "text" in event:
                if not str(event["text"]).startswith("Current CPU usage:"):
                    web_client = payload["web_client"]
                    for i in range(0, 3):
                        new_message = web_client.chat_postMessage(
                            channel=event["channel"],
                            text=
                            f"Current CPU usage: {TestRTMClient.cpu_usage} % (test_cpu_usage)",
                        )
                        self.logger.debug(new_message)
                        self.call_count += 1

        def connect():
            self.logger.debug("Starting RTM Client...")
            self.rtm_client.start()

        rtm = threading.Thread(target=connect)
        rtm.daemon = True

        rtm.start()
        time.sleep(5)

        text = "This message was sent by <https://slack.dev/python-slackclient/|python-slackclient>! (test_cpu_usage)"
        new_message = self.web_client.chat_postMessage(channel=self.channel_id,
                                                       text=text)
        self.assertFalse("error" in new_message)

        time.sleep(5)
        self.assertLess(TestRTMClient.cpu_usage, 30,
                        "Too high CPU usage detected")
        self.assertEqual(self.call_count, 3, "The RTM handler failed")

    # >       self.assertLess(TestRTMClient.cpu_usage, 30, "Too high CPU usage detected")
    # E       AssertionError: 100.2 not less than 30 : Too high CPU usage detected
    #
    # integration_tests/rtm/test_rtm_client.py:160: AssertionError

    @async_test
    async def test_cpu_usage_async(self):
        self.rtm_client = RTMClient(token=self.bot_token, run_async=True)
        self.web_client = LegacyWebClient(token=self.bot_token, run_async=True)

        self.call_count = 0
        TestRTMClient.cpu_usage = 0

        @RTMClient.run_on(event="message")
        async def send_reply_async(**payload):
            self.logger.debug(payload)
            event = payload["data"]
            if "text" in event:
                if not str(event["text"]).startswith("Current CPU usage:"):
                    web_client = payload["web_client"]
                    for i in range(0, 3):
                        new_message = await web_client.chat_postMessage(
                            channel=event["channel"],
                            text=
                            f"Current CPU usage: {TestRTMClient.cpu_usage} % (test_cpu_usage_async)",
                        )
                        self.logger.debug(new_message)
                        self.call_count += 1

        # intentionally not waiting here
        self.rtm_client.start()

        await asyncio.sleep(5)

        text = "This message was sent by <https://slack.dev/python-slackclient/|python-slackclient>! (test_cpu_usage_async)"
        new_message = await self.web_client.chat_postMessage(
            channel=self.channel_id, text=text)
        self.assertFalse("error" in new_message)

        await asyncio.sleep(5)
        self.assertLess(TestRTMClient.cpu_usage, 30,
                        "Too high CPU usage detected")
        self.assertEqual(self.call_count, 3, "The RTM handler failed")
Example #15
0
class TestRTMClient(unittest.TestCase):
    """Runs integration tests with real Slack API

    https://github.com/slackapi/python-slack-sdk/issues/631
    """

    def setUp(self):
        if not hasattr(self, "logger"):
            self.logger = logging.getLogger(__name__)
            self.channel_id = os.environ[SLACK_SDK_TEST_RTM_TEST_CHANNEL_ID]
            self.bot_token = os.environ[SLACK_SDK_TEST_CLASSIC_APP_BOT_TOKEN]

    def tearDown(self):
        # Reset the decorators by @RTMClient.run_on
        RTMClient._callbacks = collections.defaultdict(list)
        # Stop the Client
        if hasattr(self, "rtm_client") and not self.rtm_client._stopped:
            self.rtm_client.stop()

    @pytest.mark.skipif(
        condition=is_not_specified(), reason="to avoid rate_limited errors"
    )
    def test_issue_631_sharing_event_loop(self):
        self.success = None
        self.text = "This message was sent to verify issue #631"

        self.rtm_client = RTMClient(
            token=self.bot_token,
            run_async=False,
            loop=asyncio.new_event_loop(),  # TODO: this doesn't work without this
        )

        # @RTMClient.run_on(event="message")
        # def send_reply(**payload):
        #     self.logger.debug(payload)
        #     data = payload['data']
        #     web_client = payload['web_client']
        #     web_client._event_loop = self.loop
        #     # Maybe you will also need the following line uncommented
        #     # web_client.run_async = True
        #
        #     if self.text in data['text']:
        #         channel_id = data['channel']
        #         thread_ts = data['ts']
        #         try:
        #             self.success = web_client.chat_postMessage(
        #                 channel=channel_id,
        #                 text="Thanks!",
        #                 thread_ts=thread_ts
        #             )
        #         except Exception as e:
        #             # slack.rtm.client:client.py:446 When calling '#send_reply()'
        #             # in the 'test_rtm_client' module the following error was raised: This event loop is already running
        #             self.logger.error(traceback.format_exc())
        #             raise e

        # Solution (1) for #631
        @RTMClient.run_on(event="message")
        def send_reply(**payload):
            self.logger.debug(payload)
            data = payload["data"]
            web_client = payload["web_client"]

            try:
                if "text" in data and self.text in data["text"]:
                    channel_id = data["channel"]
                    thread_ts = data["ts"]
                    self.success = web_client.chat_postMessage(
                        channel=channel_id, text="Thanks!", thread_ts=thread_ts
                    )
            except Exception as e:
                self.logger.error(traceback.format_exc())
                raise e

        def connect():
            self.logger.debug("Starting RTM Client...")
            self.rtm_client.start()

        t = threading.Thread(target=connect)
        t.daemon = True
        t.start()

        try:
            self.assertIsNone(self.success)
            time.sleep(5)

            self.web_client = WebClient(
                token=self.bot_token,
                run_async=False,
            )
            new_message = self.web_client.chat_postMessage(
                channel=self.channel_id, text=self.text
            )
            self.assertFalse("error" in new_message)

            time.sleep(5)
            self.assertIsNotNone(self.success)
        finally:
            t.join(0.3)

    # Solution (2) for #631
    @pytest.mark.skipif(
        condition=is_not_specified(), reason="this is just for reference"
    )
    @async_test
    async def test_issue_631_sharing_event_loop_async(self):
        self.success = None
        self.text = "This message was sent to verify issue #631"

        # To make run_async=True, the test method needs to be an async function + @async_test decorator
        self.rtm_client = RTMClient(token=self.bot_token, run_async=True)
        self.web_client = WebClient(token=self.bot_token, run_async=True)

        @RTMClient.run_on(event="message")
        async def send_reply(**payload):
            self.logger.debug(payload)
            data = payload["data"]
            web_client = payload["web_client"]

            try:
                if "text" in data and self.text in data["text"]:
                    channel_id = data["channel"]
                    thread_ts = data["ts"]
                    self.success = await web_client.chat_postMessage(
                        channel=channel_id, text="Thanks!", thread_ts=thread_ts
                    )
            except Exception as e:
                self.logger.error(traceback.format_exc())
                raise e

        # intentionally not waiting here
        self.rtm_client.start()

        self.assertIsNone(self.success)
        await asyncio.sleep(5)

        self.web_client = WebClient(
            token=self.bot_token,
            run_async=True,  # all need to be async here
        )
        new_message = await self.web_client.chat_postMessage(
            channel=self.channel_id, text=self.text
        )
        self.assertFalse("error" in new_message)

        await asyncio.sleep(5)
        self.assertIsNotNone(self.success)
class TestRTMClient(unittest.TestCase):
    """Runs integration tests with real Slack API"""
    def setUp(self):
        if not hasattr(self, "logger"):
            self.logger = logging.getLogger(__name__)
            self.channel_id = os.environ[SLACK_SDK_TEST_RTM_TEST_CHANNEL_ID]
            self.bot_token = os.environ[SLACK_SDK_TEST_CLASSIC_APP_BOT_TOKEN]

    def tearDown(self):
        # Reset the decorators by @RTMClient.run_on
        RTMClient._callbacks = collections.defaultdict(list)
        # Stop the Client
        if hasattr(self, "rtm_client") and not self.rtm_client._stopped:
            self.rtm_client.stop()

    def test_basic_operations(self):
        self.sent_text: str = None
        self.rtm_client = RTMClient(
            token=self.bot_token,
            run_async=False,
            loop=asyncio.new_event_loop(
            ),  # TODO: this doesn't work without this
        )
        self.web_client = LegacyWebClient(token=self.bot_token)

        @RTMClient.run_on(event="message")
        def send_reply(**payload):
            self.logger.debug(payload)
            self.sent_text = payload["data"]["text"]

        def connect():
            self.logger.debug("Starting RTM Client...")
            self.rtm_client.start()

        t = threading.Thread(target=connect)
        t.setDaemon(True)
        t.start()

        try:
            self.assertIsNone(self.sent_text)
            time.sleep(5)

            text = "This message was sent by <https://slack.dev/python-slackclient/|python-slackclient>! (test_basic_operations)"
            new_message = self.web_client.chat_postMessage(
                channel=self.channel_id, text=text)
            self.assertFalse("error" in new_message)

            time.sleep(5)
            self.assertEqual(self.sent_text, text)
        finally:
            t.join(0.3)

    @async_test
    async def test_basic_operations_async(self):
        self.sent_text: str = None
        self.rtm_client = RTMClient(token=self.bot_token, run_async=True)
        self.async_web_client = LegacyWebClient(token=self.bot_token,
                                                run_async=True)

        @RTMClient.run_on(event="message")
        async def send_reply(**payload):
            self.logger.debug(payload)
            self.sent_text = payload["data"]["text"]

        # intentionally not waiting here
        self.rtm_client.start()

        self.assertIsNone(self.sent_text)
        await asyncio.sleep(5)

        text = "This message was sent by <https://slack.dev/python-slackclient/|python-slackclient>! (test_basic_operations_async)"
        new_message = await self.async_web_client.chat_postMessage(
            channel=self.channel_id, text=text)
        self.assertFalse("error" in new_message)
        await asyncio.sleep(5)
        self.assertEqual(self.sent_text, text)
Example #17
0
class TestRTMClient(unittest.TestCase):
    """Runs integration tests with real Slack API

    https://github.com/slackapi/python-slack-sdk/issues/701
    """
    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.bot_token = os.environ[SLACK_SDK_TEST_CLASSIC_APP_BOT_TOKEN]

    def tearDown(self):
        # Reset the decorators by @RTMClient.run_on
        RTMClient._callbacks = collections.defaultdict(list)

    # @pytest.mark.skipif(condition=is_not_specified(), reason="to avoid rate_limited errors")
    @pytest.mark.skip()
    def test_receiving_all_messages(self):
        self.rtm_client = RTMClient(token=self.bot_token,
                                    loop=asyncio.new_event_loop())
        self.web_client = WebClient(token=self.bot_token)

        self.call_count = 0

        @RTMClient.run_on(event="message")
        def send_reply(**payload):
            self.logger.debug(payload)
            web_client, data = payload["web_client"], payload["data"]
            web_client.reactions_add(channel=data["channel"],
                                     timestamp=data["ts"],
                                     name="eyes")
            self.call_count += 1

        def connect():
            self.logger.debug("Starting RTM Client...")
            self.rtm_client.start()

        rtm = threading.Thread(target=connect)
        rtm.daemon = True

        rtm.start()
        time.sleep(3)

        total_num = 10

        sender_completion = []

        def sent_bulk_message():
            for i in range(total_num):
                text = f"Sent by <https://slack.dev/python-slackclient/|python-slackclient>! ({i})"
                self.web_client.chat_postMessage(channel="#random", text=text)
                time.sleep(0.1)
            sender_completion.append(True)

        num_of_senders = 3
        senders = []
        for sender_num in range(num_of_senders):
            sender = threading.Thread(target=sent_bulk_message)
            sender.daemon = True
            sender.start()
            senders.append(sender)

        while len(sender_completion) < num_of_senders:
            time.sleep(1)

        expected_call_count = total_num * num_of_senders
        wait_seconds = 0
        max_wait = 20
        while self.call_count < expected_call_count and wait_seconds < max_wait:
            time.sleep(1)
            wait_seconds += 1

        self.assertEqual(total_num * num_of_senders, self.call_count,
                         "The RTM handler failed")

    @pytest.mark.skipif(condition=is_not_specified(),
                        reason="to avoid rate_limited errors")
    @async_test
    async def test_receiving_all_messages_async(self):
        self.rtm_client = RTMClient(token=self.bot_token, run_async=True)
        self.web_client = WebClient(token=self.bot_token, run_async=False)

        self.call_count = 0

        @RTMClient.run_on(event="message")
        async def send_reply(**payload):
            self.logger.debug(payload)
            web_client, data = payload["web_client"], payload["data"]
            await web_client.reactions_add(channel=data["channel"],
                                           timestamp=data["ts"],
                                           name="eyes")
            self.call_count += 1

        # intentionally not waiting here
        self.rtm_client.start()

        await asyncio.sleep(3)

        total_num = 10

        sender_completion = []

        def sent_bulk_message():
            for i in range(total_num):
                text = f"Sent by <https://slack.dev/python-slackclient/|python-slackclient>! ({i})"
                self.web_client.chat_postMessage(channel="#random", text=text)
                time.sleep(0.1)
            sender_completion.append(True)

        num_of_senders = 3
        senders = []
        for sender_num in range(num_of_senders):
            sender = threading.Thread(target=sent_bulk_message)
            sender.daemon = True
            sender.start()
            senders.append(sender)

        while len(sender_completion) < num_of_senders:
            await asyncio.sleep(1)

        expected_call_count = total_num * num_of_senders
        wait_seconds = 0
        max_wait = 20
        while self.call_count < expected_call_count and wait_seconds < max_wait:
            await asyncio.sleep(1)
            wait_seconds += 1

        self.assertEqual(total_num * num_of_senders, self.call_count,
                         "The RTM handler failed")
Example #18
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,mpim,im')
        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.identifier
                                for c in self._channels.values()]))

        puts("Final initialization of plugins...")
        for instance, class_name in self._plugins:
            instance.init_final()
            show_valid(class_name)

    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.conversations_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.conversations_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, plugins):
        self._plugins = plugins
        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='group_joined', callback=self._on_channel_created)
        RTMClient.on(event='mpim_joined', callback=self._on_channel_created)
        RTMClient.on(event='im_created', callback=self._on_channel_created)
        RTMClient.on(event='channel_deleted',
                     callback=self._on_channel_deleted)
        RTMClient.on(event='im_close', 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