Пример #1
0
    async def _dispatch_event(self, event, data=None):
        """Dispatches the event and executes any associated callbacks.

        Note: To prevent the app from crashing due to callback errors. We
        catch all exceptions and send all data to the logger.

        Args:
            event (str): The type of event. e.g. 'bot_added'
            data (dict): The data Slack sent. e.g.
            {
                "type": "bot_added",
                "bot": {
                    "id": "B024BE7LH",
                    "app_id": "A4H1JB4AZ",
                    "name": "hugbot"
                }
            }
        """
        if self._logger.level <= logging.DEBUG:
            self._logger.debug("Received an event: '%s' - %s", event, data)
        for callback in self._callbacks[event]:
            self._logger.debug(
                "Running %s callbacks for event: '%s'",
                len(self._callbacks[event]),
                event,
            )
            try:
                if self._stopped and event not in ["close", "error"]:
                    # Don't run callbacks if client was stopped unless they're
                    # close/error callbacks.
                    break

                if inspect.iscoroutinefunction(callback):
                    await callback(rtm_client=self,
                                   web_client=self._web_client,
                                   data=data)
                else:
                    if self.run_async is True:
                        raise client_err.SlackRequestError(
                            f'The callback "{callback.__name__}" is NOT a coroutine. '
                            "Running such with run_async=True is unsupported. "
                            "Consider adding async/await to the method "
                            "or going with run_async=False if your app is not really non-blocking."
                        )
                    payload = {
                        "rtm_client": self,
                        "web_client": self._web_client,
                        "data": data,
                    }
                    callback(**payload)
            except Exception as err:
                name = callback.__name__
                module = callback.__module__
                msg = f"When calling '#{name}()' in the '{module}' module the following error was raised: {err}"
                self._logger.error(msg)
                raise
Пример #2
0
    def api_call(
        self,
        api_method: str,
        *,
        http_verb: str = "POST",
        files: dict = None,
        data: Union[dict, FormData] = None,
        params: dict = None,
        json: dict = None,
        headers: dict = None,
        auth: dict = None,
    ) -> Union[asyncio.Future, SlackResponse]:
        """Create a request and execute the API call to Slack.

        Args:
            api_method (str): The target Slack API method.
                e.g. 'chat.postMessage'
            http_verb (str): HTTP Verb. e.g. 'POST'
            files (dict): Files to multipart upload.
                e.g. {imageORfile: file_objectORfile_path}
            data: The body to attach to the request. If a dictionary is
                provided, form-encoding will take place.
                e.g. {'key1': 'value1', 'key2': 'value2'}
            params (dict): The URL parameters to append to the URL.
                e.g. {'key1': 'value1', 'key2': 'value2'}
            json (dict): JSON for the body to attach to the request
                (if files or data is not specified).
                e.g. {'key1': 'value1', 'key2': 'value2'}

        Returns:
            (SlackResponse)
                The server's response to an HTTP request. Data
                from the response can be accessed like a dict.
                If the response included 'next_cursor' it can
                be iterated on to execute subsequent requests.

        Raises:
            SlackApiError: The following Slack API call failed:
                'chat.postMessage'.
            SlackRequestError: Json data can only be submitted as
                POST requests.
        """
        has_json = json is not None
        has_files = files is not None
        if has_json and http_verb != "POST":
            msg = "Json data can only be submitted as POST requests. GET requests should use the 'params' argument."
            raise err.SlackRequestError(msg)

        api_url = self._get_url(api_method)

        if auth:
            auth = BasicAuth(auth["client_id"], auth["client_secret"])

        if data:
            data = {k: v for k, v in data.items() if v is not None}
        if files:
            files = {k: v for k, v in files.items() if v is not None}
        if params:
            params = {k: v for k, v in params.items() if v is not None}

        req_args = {
            "headers": self._get_headers(has_json, has_files, headers),
            "data": data,
            "files": files,
            "params": params,
            "json": json,
            "ssl": self.ssl,
            "proxy": self.proxy,
            "auth": auth,
        }

        if self._event_loop is None:
            self._event_loop = self._get_event_loop()

        show_2020_01_deprecation(api_method)
        future = asyncio.ensure_future(
            self._send(http_verb=http_verb, api_url=api_url, req_args=req_args),
            loop=self._event_loop,
        )

        if self.run_async:
            return future

        return self._event_loop.run_until_complete(future)
Пример #3
0
    def api_call(
        self,
        api_method: str,
        *,
        http_verb: str = "POST",
        files: dict = None,
        data: dict = None,
        params: dict = None,
        json: dict = None,
    ):
        """Create a request and execute the API call to Slack.

        Args:
            api_method (str): The target Slack API method.
                e.g. 'chat.postMessage'
            http_verb (str): HTTP Verb. e.g. 'POST'
            files (dict): Files to multipart upload.
                e.g. {imageORfile: file_objectORfile_path}
            data: The body to attach to the request. If a dictionary is
                provided, form-encoding will take place.
                e.g. {'key1': 'value1', 'key2': 'value2'}
            params (dict): The URL parameters to append to the URL.
                e.g. {'key1': 'value1', 'key2': 'value2'}
            json (dict): JSON for the body to attach to the request
                (if files or data is not specified).
                e.g. {'key1': 'value1', 'key2': 'value2'}

        Returns:
            (SlackResponse)
                The server's response to an HTTP request. Data
                from the response can be accessed like a dict.
                If the response included 'next_cursor' it can
                be iterated on to execute subsequent requests.

        Raises:
            SlackApiError: The following Slack API call failed:
                'chat.postMessage'.
            SlackRequestError: Json data can only be submitted as
                POST requests.
        """
        if json is not None and http_verb != "POST":
            msg = "Json data can only be submitted as POST requests. GET requests should use the 'params' argument."
            raise err.SlackRequestError(msg)

        api_url = self._get_url(api_method)
        headers = {
            "User-Agent": self._get_user_agent(),
            "Authorization": "Bearer {}".format(self.token),
        }
        if files is not None:
            form_data = aiohttp.FormData()
            for k, v in files.items():
                if isinstance(v, str):
                    form_data.add_field(k, open(v, "rb"))
                else:
                    form_data.add_field(k, v)

            if data is not None:
                for k, v in data.items():
                    form_data.add_field(k, str(v))

            data = form_data

        req_args = {
            "headers": headers,
            "data": data,
            "params": params,
            "json": json,
            "ssl": self.ssl,
            "proxy": self.proxy,
        }

        if self._event_loop is None:
            self._set_event_loop()

        future = asyncio.ensure_future(
            self._send(http_verb=http_verb, api_url=api_url,
                       req_args=req_args),
            loop=self._event_loop,
        )

        if self.run_async or self._event_loop.is_running():
            return future

        return self._event_loop.run_until_complete(future)