Example #1
0
    def __init__(self, config, opsdroid=None):
        """Create the connector."""
        super().__init__(config, opsdroid=opsdroid)
        _LOGGER.debug(_("Starting Slack connector."))
        self.name = "slack"
        self.bot_token = config["bot-token"]
        self.bot_name = config.get("bot-name", "opsdroid")
        self.default_target = config.get("default-room", "#general")
        self.icon_emoji = config.get("icon-emoji", ":robot_face:")
        self.start_thread = config.get("start_thread", False)
        self.socket_mode = config.get("socket-mode", True)
        self.app_token = config.get("app-token")
        self.ssl_context = ssl.create_default_context(cafile=certifi.where())
        self.slack_web_client = AsyncWebClient(
            token=self.bot_token,
            ssl=self.ssl_context,
            proxy=os.environ.get("HTTPS_PROXY"),
        )
        self.socket_mode_client = (SocketModeClient(
            self.app_token, web_client=self.slack_web_client)
                                   if self.app_token else None)
        self.auth_info = None
        self.user_info = None
        self.bot_id = None
        self.known_users = {}

        self._event_creator = SlackEventCreator(self)
Example #2
0
    def __init__(  # type: ignore
        self,
        app: App,  # type: ignore
        app_token: Optional[str] = None,
        logger: Optional[Logger] = None,
        web_client: Optional[AsyncWebClient] = None,
        proxy: Optional[str] = None,
        ping_interval: float = 10,
    ):
        """Socket Mode adapter for Bolt apps

        Args:
            app: The Bolt app
            app_token: App-level token starting with `xapp-`
            logger: Custom logger
            web_client: custom `slack_sdk.web.WebClient` instance
            proxy: HTTP proxy URL
            ping_interval: The ping-pong internal (seconds)
        """
        self.app = app
        self.app_token = app_token or os.environ["SLACK_APP_TOKEN"]
        self.client = SocketModeClient(
            app_token=self.app_token,
            logger=logger if logger is not None else app.logger,
            web_client=web_client if web_client is not None else app.client,
            proxy=proxy,
            ping_interval=ping_interval,
        )
        self.client.socket_mode_request_listeners.append(self.handle)
Example #3
0
async def run_websocket_process():
    from slack_sdk.socket_mode.aiohttp import SocketModeClient
    from slack_sdk.socket_mode.response import SocketModeResponse
    from slack_sdk.socket_mode.request import SocketModeRequest

    if not SLACK_SOCKET_MODE_APP_TOKEN:
        log.error("SLACK_SOCKET_MODE_APP_TOKEN not defined in .env file.")
        return

    # Initialize SocketModeClient with an app-level token + WebClient
    client = SocketModeClient(
        # This app-level token will be used only for establishing a connection
        app_token=str(SLACK_SOCKET_MODE_APP_TOKEN),  # xapp-A111-222-xyz
        # You will be using this WebClient for performing Web API calls in listeners
        web_client=AsyncWebClient(
            token=str(SLACK_API_BOT_TOKEN)),  # xoxb-111-222-xyz
    )

    async def process(client: SocketModeClient, req: SocketModeRequest):
        db_session = SessionLocal()
        background_tasks = BackgroundTasks()

        if req.type == "events_api":
            response = await handle_slack_event(
                db_session=db_session,
                client=client.web_client,
                event=EventEnvelope(**req.payload),
                background_tasks=background_tasks,
            )

        if req.type == "slash_commands":
            response = await handle_slack_command(
                db_session=db_session,
                client=client.web_client,
                request=req.payload,
                background_tasks=background_tasks,
            )

        if req.type == "interactive":
            response = await handle_slack_action(
                db_session=db_session,
                client=client.web_client,
                request=req.payload,
                background_tasks=background_tasks,
            )

        response = SocketModeResponse(envelope_id=req.envelope_id,
                                      payload=response)
        await client.send_socket_mode_response(response)

        # run the background tasks
        await background_tasks()

    # Add a new listener to receive messages from Slack
    # You can add more listeners like this
    client.socket_mode_request_listeners.append(process)
    # Establish a WebSocket connection to the Socket Mode servers
    await client.connect()
    await asyncio.sleep(float("inf"))
Example #4
0
 async def test_issue_new_wss_url(self):
     client = SocketModeClient(
         app_token="xapp-A111-222-xyz",
         web_client=self.web_client,
         auto_reconnect_enabled=False,
     )
     url = await client.issue_new_wss_url()
     self.assertTrue(url.startswith("wss://"))
Example #5
0
 def __init__(  # type: ignore
     self,
     app: AsyncApp,  # type: ignore
     app_token: Optional[str] = None,
 ):
     self.app = app
     self.app_token = app_token or os.environ["SLACK_APP_TOKEN"]
     self.client = SocketModeClient(app_token=self.app_token)
     self.client.socket_mode_request_listeners.append(self.handle)
Example #6
0
 async def test_init_close(self):
     client = SocketModeClient(
         app_token="xapp-A111-222-xyz",
         web_client=self.web_client,
         auto_reconnect_enabled=False,
     )
     try:
         self.assertIsNotNone(client)
     finally:
         await client.close()
Example #7
0
 async def test_connect_to_new_endpoint(self):
     client = SocketModeClient(
         app_token="xapp-A111-222-xyz",
         web_client=self.web_client,
         auto_reconnect_enabled=False,
     )
     try:
         await client.connect_to_new_endpoint()
     except Exception as e:
         # TODO: valida test to connect
         pass
     finally:
         await client.close()
Example #8
0
    async def test_send_message_while_disconnection(self):
        if is_ci_unstable_test_skip_enabled():
            return
        t = Thread(target=start_socket_mode_server(self, 3001))
        t.daemon = True
        t.start()

        client = SocketModeClient(
            app_token="xapp-A111-222-xyz",
            web_client=self.web_client,
            auto_reconnect_enabled=False,
            trace_enabled=True,
        )

        try:
            time.sleep(1)  # wait for the server
            client.wss_uri = "ws://0.0.0.0:3001/link"
            await client.connect()
            await asyncio.sleep(1)  # wait for the message receiver
            await client.send_message("foo")

            await client.disconnect()
            await asyncio.sleep(1)  # wait for the message receiver
            try:
                await client.send_message("foo")
                self.fail("ConnectionError is expected here")
            except ConnectionError as _:
                pass

            await client.connect()
            await asyncio.sleep(1)  # wait for the message receiver
            await client.send_message("foo")
        finally:
            await client.close()
            self.server.stop()
            self.server.close()
Example #9
0
    async def test_enqueue_message(self):
        client = SocketModeClient(
            app_token="xapp-A111-222-xyz",
            web_client=self.web_client,
            auto_reconnect_enabled=False,
            on_message_listeners=[lambda msg: None],
        )
        client.message_listeners.append(listener)
        try:
            await client.enqueue_message("hello")
            await client.process_message()

            await client.enqueue_message(
                """{"type":"hello","num_connections":1,"debug_info":{"host":"applink-111-222","build_number":10,"approximate_connection_time":18060},"connection_info":{"app_id":"A111"}}"""
            )
            await client.process_message()
        finally:
            await client.close()
Example #10
0
 def __init__(  # type: ignore
     self,
     app: AsyncApp,  # type: ignore
     app_token: Optional[str] = None,
     logger: Optional[Logger] = None,
     web_client: Optional[AsyncWebClient] = None,
     proxy: Optional[str] = None,
     ping_interval: float = 10,
 ):
     self.app = app
     self.app_token = app_token or os.environ["SLACK_APP_TOKEN"]
     self.client = SocketModeClient(
         app_token=self.app_token,
         logger=logger if logger is not None else app.logger,
         web_client=web_client if web_client is not None else app.client,
         proxy=proxy,
         ping_interval=ping_interval,
     )
     self.client.socket_mode_request_listeners.append(self.handle)
Example #11
0
async def main():

    client = SocketModeClient(
        app_token=os.environ.get("SLACK_SDK_TEST_SOCKET_MODE_APP_TOKEN"),
        web_client=AsyncWebClient(
            token=os.environ.get("SLACK_SDK_TEST_SOCKET_MODE_BOT_TOKEN")),
    )

    async def process(client: SocketModeClient, req: SocketModeRequest):
        if req.type == "events_api":
            response = SocketModeResponse(envelope_id=req.envelope_id)
            await client.send_socket_mode_response(response)

            await client.web_client.reactions_add(
                name="eyes",
                channel=req.payload["event"]["channel"],
                timestamp=req.payload["event"]["ts"],
            )

    client.socket_mode_request_listeners.append(process)
    await client.connect()
    await asyncio.sleep(float("inf"))
    async def test_interactions(self):
        t = Thread(target=start_socket_mode_server(self, 3001))
        t.daemon = True
        t.start()

        received_messages = []
        received_socket_mode_requests = []

        async def message_handler(message: WSMessage):
            self.logger.info(f"Raw Message: {message}")
            await asyncio.sleep(randint(50, 200) / 1000)
            received_messages.append(message.data)

        async def socket_mode_listener(
            self: AsyncBaseSocketModeClient, request: SocketModeRequest,
        ):
            self.logger.info(f"Socket Mode Request: {request.payload}")
            await asyncio.sleep(randint(50, 200) / 1000)
            received_socket_mode_requests.append(request.payload)

        client = SocketModeClient(
            app_token="xapp-A111-222-xyz",
            web_client=self.web_client,
            on_message_listeners=[message_handler],
            auto_reconnect_enabled=False,
        )
        client.socket_mode_request_listeners.append(socket_mode_listener)

        try:
            time.sleep(1)  # wait for the server
            client.wss_uri = "ws://0.0.0.0:3001/link"
            await client.connect()
            await asyncio.sleep(1)  # wait for the message receiver

            for _ in range(10):
                await client.send_message("foo")
                await client.send_message("bar")
                await client.send_message("baz")

            expected = (
                socket_mode_envelopes
                + [socket_mode_hello_message]
                + ["foo", "bar", "baz"] * 10
            )
            expected.sort()
            expected.sort()

            count = 0
            while count < 10 and len(received_messages) < len(expected):
                await asyncio.sleep(0.2)
                count += 0.2

            received_messages.sort()
            self.assertEqual(received_messages, expected)

            self.assertEqual(
                len(socket_mode_envelopes), len(received_socket_mode_requests)
            )
        finally:
            await client.close()
            self.server.stop()
            self.server.close()
Example #13
0
async def main():
    client = SocketModeClient(app_token=os.environ["SLACK_APP_TOKEN"])
    await client.connect()
    await asyncio.sleep(3)
    await client.close()
Example #14
0
async def run_websocket_process(config):
    from slack_sdk.socket_mode.aiohttp import SocketModeClient
    from slack_sdk.socket_mode.response import SocketModeResponse
    from slack_sdk.socket_mode.request import SocketModeRequest

    # Initialize SocketModeClient with an app-level token + WebClient
    client = SocketModeClient(
        # This app-level token will be used only for establishing a connection
        app_token=config.socket_mode_app_token.get_secret_value(
        ),  # xapp-A111-222-xyz
        # You will be using this WebClient for performing Web API calls in listeners
        web_client=AsyncWebClient(
            token=config.api_bot_token.get_secret_value()),  # xoxb-111-222-xyz
    )

    async def process(client: SocketModeClient, req: SocketModeRequest):
        background_tasks = BackgroundTasks()

        if req.type == "events_api":
            response = await handle_slack_event(
                config=config,
                client=client.web_client,
                event=EventEnvelope(**req.payload),
                background_tasks=background_tasks,
            )

        if req.type == "slash_commands":
            response = await handle_slack_command(
                config=config,
                client=client.web_client,
                request=req.payload,
                background_tasks=background_tasks,
            )

        if req.type == "interactive":
            if req.payload["type"] == "block_suggestion":
                response = await handle_slack_menu(
                    config=config,
                    client=client.web_client,
                    request=req.payload,
                )

            else:
                response = await handle_slack_action(
                    config=config,
                    client=client.web_client,
                    request=req.payload,
                    background_tasks=background_tasks,
                )

        response = SocketModeResponse(envelope_id=req.envelope_id,
                                      payload=response)
        await client.send_socket_mode_response(response)

        # run the background tasks
        await background_tasks()

    # Add a new listener to receive messages from Slack
    # You can add more listeners like this
    client.socket_mode_request_listeners.append(process)
    # Establish a WebSocket connection to the Socket Mode servers
    await client.connect()
    await asyncio.sleep(float("inf"))