def stop_on_open(**payload): rtm_client = payload["rtm_client"] if rtm_client._connection_attempts == 1: raise e.SlackApiError("Test Error", {"headers": {"Retry-After": 0.001}}) else: self.assertEqual(rtm_client._connection_attempts, 2) rtm_client.stop()
async def _retrieve_websocket_info(self): """Retrieves the WebSocket info from Slack. Returns: A tuple of websocket information. e.g. ( "wss://...", { "self": {"id": "U01234ABC","name": "robotoverlord"}, "team": { "domain": "exampledomain", "id": "T123450FP", "name": "ExampleName" } } ) Raises: SlackApiError: Unable to retrieve RTM URL from Slack. """ if self._web_client is None: self._web_client = WebClient( token=self.token, base_url=self.base_url, timeout=self.timeout, ssl=self.ssl, proxy=self.proxy, run_async=True, loop=self._event_loop, session=self._session, headers=self.headers, ) self._logger.debug("Retrieving websocket info.") use_rtm_start = self.connect_method in ["rtm.start", "rtm_start"] if self.run_async: if use_rtm_start: resp = await self._web_client.rtm_start() else: resp = await self._web_client.rtm_connect() else: if use_rtm_start: resp = self._web_client.rtm_start() else: resp = self._web_client.rtm_connect() url = resp.get("url") if url is None: msg = "Unable to retrieve RTM URL from Slack." raise client_err.SlackApiError(message=msg, response=resp) return url, resp.data
def validate(self): """Check if the response from Slack was successful. Returns: (AsyncSlackResponse) This method returns it's own object. e.g. 'self' Raises: SlackApiError: The request to the Slack API failed. """ if self.status_code == 200 and self.data and self.data.get( "ok", False): return self msg = "The request to the Slack API failed." raise e.SlackApiError(message=msg, response=self)
def validate(self): """Check if the response from Slack was successful. Returns: (SlackResponse) This method returns it's own object. e.g. 'self' Raises: SlackApiError: The request to the Slack API failed. """ if self.status_code == 200 and self.data.get("ok", False): self._logger.debug("Received the following response: %s", self.data) return self msg = "The request to the Slack API failed." raise e.SlackApiError(message=msg, response=self)
def validate(self): """Check if the response from Slack was successful. Returns: (SlackResponse) This method returns it's own object. e.g. 'self' Raises: SlackApiError: The request to the Slack API failed. """ if self._logger.level <= logging.DEBUG: self._logger.debug("Received the following response - " f"status: {self.status_code}, " f"headers: {dict(self.headers)}, " f"body: {self.data}") if self.status_code == 200 and self.data and self.data.get( "ok", False): return self msg = "The request to the Slack API failed." raise e.SlackApiError(message=msg, response=self)
async def _request(self, *, http_verb, api_url, req_args): """Submit the HTTP request with the running session or a new session. Returns: A dictionary of the response data. """ session = None use_running_session = self.session and not self.session.closed if use_running_session: session = self.session else: session = aiohttp.ClientSession( timeout=aiohttp.ClientTimeout(total=self.timeout), auth=req_args.pop("auth", None), ) response = None try: async with session.request(http_verb, api_url, **req_args) as res: data = {} try: data = await res.json() except aiohttp.ContentTypeError: self._logger.debug( f"No response data returned from the following API call: {api_url}." ) except json.decoder.JSONDecodeError as e: message = f"Failed to parse the response body: {str(e)}" raise err.SlackApiError(message, res) response = { "data": data, "headers": res.headers, "status_code": res.status, } finally: if not use_running_session: await session.close() return response
def _urllib_api_call( self, *, token: str = None, url: str, query_params: Dict[str, str] = {}, json_body: Dict = {}, body_params: Dict[str, str] = {}, files: Dict[str, io.BytesIO] = {}, additional_headers: Dict[str, str] = {}, ) -> SlackResponse: """Performs a Slack API request and returns the result. :param token: Slack API Token (either bot token or user token) :param url: a complete URL (e.g., https://www.slack.com/api/chat.postMessage) :param query_params: query string :param json_body: json data structure (it's still a dict at this point), if you give this argument, body_params and files will be skipped :param body_params: form params :param files: files to upload :param additional_headers: request headers to append :return: API response """ files_to_close: List[BinaryIO] = [] try: # True/False -> "1"/"0" query_params = convert_bool_to_0_or_1(query_params) body_params = convert_bool_to_0_or_1(body_params) if self._logger.level <= logging.DEBUG: def convert_params(values: dict) -> dict: if not values or not isinstance(values, dict): return {} return { k: ("(bytes)" if isinstance(v, bytes) else v) for k, v in values.items() } headers = { k: "(redacted)" if k.lower() == "authorization" else v for k, v in additional_headers.items() } self._logger.debug( f"Sending a request - url: {url}, " f"query_params: {convert_params(query_params)}, " f"body_params: {convert_params(body_params)}, " f"files: {convert_params(files)}, " f"json_body: {json_body}, " f"headers: {headers}") request_data = {} if files is not None and isinstance(files, dict) and len(files) > 0: if body_params: for k, v in body_params.items(): request_data.update({k: v}) for k, v in files.items(): if isinstance(v, str): f: BinaryIO = open(v.encode("utf-8", "ignore"), "rb") files_to_close.append(f) request_data.update({k: f}) elif isinstance(v, (bytearray, bytes)): request_data.update({k: io.BytesIO(v)}) else: request_data.update({k: v}) request_headers = self._build_urllib_request_headers( token=token or self.token, has_json=json is not None, has_files=files is not None, additional_headers=additional_headers, ) request_args = { "headers": request_headers, "data": request_data, "params": body_params, "files": files, "json": json_body, } if query_params: q = urlencode(query_params) url = f"{url}&{q}" if "?" in url else f"{url}?{q}" response = self._perform_urllib_http_request(url=url, args=request_args) if response.get("body"): try: response_body_data: dict = json.loads(response["body"]) except json.decoder.JSONDecodeError as e: message = f"Failed to parse the response body: {str(e)}" raise err.SlackApiError(message, response) else: response_body_data: dict = None if query_params: all_params = copy.copy(body_params) all_params.update(query_params) else: all_params = body_params request_args["params"] = all_params # for backward-compatibility return SlackResponse( client=self, http_verb="POST", # you can use POST method for all the Web APIs api_url=url, req_args=request_args, data=response_body_data, headers=dict(response["headers"]), status_code=response["status"], use_sync_aiohttp=False, ).validate() finally: for f in files_to_close: if not f.closed: f.close()