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)
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)
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"))
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://"))
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)
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()
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()
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()
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()
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)
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()
async def main(): client = SocketModeClient(app_token=os.environ["SLACK_APP_TOKEN"]) await client.connect() await asyncio.sleep(3) await client.close()
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"))