o
    aqe\                     @   s   d Z ddlZddlZddlZddlZddlZddlZddlZddlmZ ddl	m
Z
 ddlmZmZ ddlmZ ddlmZmZmZ ddlZddlmZ ddlmZ G d	d
 d
ZdS )z5A Python module for interacting with Slack's RTM API.    N)Future)
SSLContext)current_threadmain_thread)List)OptionalCallableDefaultDict)	WebClientc                   @   sd  e Zd ZU dZeeZee	d< ddddde
jdddi d
ded	ee d
ee dee dee dee dee dee dee deej dee fddZedefddZededefddZdejfddZdd Zd d! Zd"efd#d$Zd%d& Zd'd( Z d)efd*d+Z!ed,d- Z"d.d/ Z#d0d1 Z$d2d3 Z%d=d4d5Z&d6d7 Z'd>d9d:Z(de)e fd;d<Z*dS )?	RTMClienta  An RTMClient allows apps to communicate with the Slack Platform's RTM API.

    The event-driven architecture of this client allows you to simply
    link callbacks to their corresponding events. When an event occurs
    this client executes your callback while passing along any
    information it receives.

    Attributes:
        token (str): A string specifying an xoxp or xoxb token.
        run_async (bool): A boolean specifying if the client should
            be run in async mode. Default is False.
        auto_reconnect (bool): When true the client will automatically
            reconnect when (not manually) disconnected. Default is True.
        ssl (SSLContext): To use SSL support, pass an SSLContext object here.
            Default is None.
        proxy (str): To use proxy support, pass the string of the proxy server.
            e.g. "http://proxy.com"
            Authentication credentials can be passed in proxy URL.
            e.g. "http://user:pass@some.proxy.com"
            Default is None.
        timeout (int): The amount of seconds the session should wait before timing out.
            Default is 30.
        base_url (str): The base url for all HTTP requests.
            Note: This is only used in the WebClient.
            Default is "https://www.slack.com/api/".
        connect_method (str): An string specifying if the client
            will connect with `rtm.connect` or `rtm.start`.
            Default is `rtm.connect`.
        ping_interval (int): automatically send "ping" command every
            specified period of seconds. If set to 0, do not send automatically.
            Default is 30.
        loop (AbstractEventLoop): An event loop provided by asyncio.
            If None is specified we attempt to use the current loop
            with `get_event_loop`. Default is None.

    Methods:
        ping: Sends a ping message over the websocket to Slack.
        typing: Sends a typing indicator to the specified channel.
        on: Stores and links callbacks to websocket and Slack events.
        run_on: Decorator that stores and links callbacks to websocket and Slack events.
        start: Starts an RTM Session with Slack.
        stop: Closes the websocket connection and ensures it won't reconnect.

    Example:
    ```python
    import os
    from slack import RTMClient

    @RTMClient.run_on(event="message")
    def say_hello(**payload):
        data = payload['data']
        web_client = payload['web_client']
        if 'Hello' in data['text']:
            channel_id = data['channel']
            thread_ts = data['ts']
            user = data['user']

            web_client.chat_postMessage(
                channel=channel_id,
                text=f"Hi <@{user}>!",
                thread_ts=thread_ts
            )

    slack_token = os.environ["SLACK_API_TOKEN"]
    rtm_client = RTMClient(token=slack_token)
    rtm_client.start()
    ```

    Note:
        The initial state returned when establishing an RTM connection will
        be available as the data in payload for the 'open' event. This data is not and
        will not be stored on the RTM Client.

        Any attributes or methods prefixed with _underscores are
        intended to be "private" internal use only. They may be changed or
        removed at anytime.
    
_callbacksFTN   )
	run_asyncauto_reconnectsslproxytimeoutbase_urlconnect_methodping_intervalloopheaderstokenr   r   r   r   r   r   r   r   r   r   c                C   s   |  | _|| _|| _|| _|| _|| _|| _|| _|	| _	|| _
|
p%t | _d | _d | _d | _tt| _d| _d| _d| _t| j| j| j| j| j| j| j| j| j
d	| _d S )Nr   F	r   r   r   r   r   r   r   sessionr   )stripr   r   r   r   r   r   r   r   r   r   asyncioget_event_loop_event_loop_web_client
_websocket_sessionlogging	getLogger__name___logger_last_message_id_connection_attempts_stoppedr
   )selfr   r   r   r   r   r   r   r   r   r   r    r*   Q/var/www/html/humari/django-venv/lib/python3.10/site-packages/slack/rtm/client.py__init__g   s:   
zRTMClient.__init__eventc                    s    fdd}|S )z5A decorator to store and link a callback to an event.c                    s   t j | d | S )N)r-   callback)r   on)r.   r-   r*   r+   	decorator   s   z#RTMClient.run_on.<locals>.decoratorr*   )r-   r1   r*   r0   r+   run_on   s   zRTMClient.run_onr.   c                C   s`   t |tr!|D ]}| | q| j| }tt|| | j|< dS | | | j| | dS )aP  Stores and links the callback(s) to the event.

        Args:
            event (str): A string that specifies a Slack or websocket event.
                e.g. 'channel_joined' or 'open'
            callback (Callable): Any object or a list of objects that can be called.
                e.g. <function say_hello at 0x101234567> or
                [<function say_hello at 0x10123>,<function say_bye at 0x10456>]

        Raises:
            SlackClientError: The specified callback is not callable.
            SlackClientError: The callback must accept keyword arguments (**kwargs).
        N)
isinstancelist_validate_callbackr   setappend)clsr-   r.   cbprevious_callbacksr*   r*   r+   r/      s   


zRTMClient.onreturnc                 C   sj   t jdkr t t kr tjtjtjf}|D ]
}| j	|| j
 qtj|  | jd}| jr/|S | j|S )a  Starts an RTM Session with Slack.

        Makes an authenticated call to Slack's RTM API to retrieve
        a websocket URL and then connects to the message server.
        As events stream-in we run any associated callbacks stored
        on the client.

        If 'auto_reconnect' is specified we
        retrieve a new url and reconnect any time the connection
        is lost unintentionally or an exception is thrown.

        Raises:
            SlackApiError: Unable to retrieve RTM URL from Slack.
        ntr   )osnamer   r   signalSIGHUPSIGTERMSIGINTr   add_signal_handlerstopr   ensure_future_connect_and_readr   run_until_complete)r)   signalssfuturer*   r*   r+   start   s   zRTMClient.startc                 C   s   | j d d| _|   dS )al  Closes the websocket connection and ensures it won't reconnect.

        If your application outputs the following errors,
        call #async_stop() instead and await for the completion on your application side.

        asyncio/base_events.py:641: RuntimeWarning:
          coroutine 'ClientWebSocketResponse.close' was never awaited self._ready.clear()
        %The Slack RTMClient is shutting down.TN)r%   debugr(   _close_websocketr)   r*   r*   r+   rE      s   	zRTMClient.stopc                    s4   | j d |  }|D ]}|I dH  qd| _dS )z?Closes the websocket connection and ensures it won't reconnect.rM   NT)r%   rN   rO   r(   )r)   remaining_futuresrK   r*   r*   r+   
async_stop   s   
zRTMClient.async_stoppayloadc                C   s   t j| || jdS )a0  Sends a message to Slack over the WebSocket connection.

        Note:
            The RTM API only supports posting simple messages formatted using
            our default message formatting mode. It does not support
            attachments or other message formatting modes. For this reason
            we recommend users send messages via the Web API methods.
            e.g. web_client.chat_postMessage()

            If the message "id" is not specified in the payload, it'll be added.

        Args:
            payload (dict): The message to send over the wesocket.
            e.g.
            {
                "id": 1,
                "type": "typing",
                "channel": "C024BE91L"
            }

        Raises:
            SlackClientNotConnectedError: Websocket connection is closed.
        r=   )r   rF   
_send_jsonr   r)   rS   r*   r*   r+   send_over_websocket   s   zRTMClient.send_over_websocketc                    sF   | j d u s| jd u rtdd|vr|  |d< | j |I d H S )NzWebsocket connection is closed.id)r    r   
client_errSlackClientNotConnectedError_next_msg_id	send_jsonrU   r*   r*   r+   rT      s   zRTMClient._send_jsonc                    s&   |   dd}| j|dI dH  dS )a  Sends a ping message over the websocket to Slack.

        Not all web browsers support the WebSocket ping spec,
        so the RTM protocol also supports ping/pong messages.

        Raises:
            SlackClientNotConnectedError: Websocket connection is closed.
        ping)rW   typerS   NrZ   rT   rU   r*   r*   r+   r\   
  s   	zRTMClient.pingchannelc                   s(   |   d|d}| j|dI dH  dS )aD  Sends a typing indicator to the specified channel.

        This indicates that this app is currently
        writing a message to send to a channel.

        Args:
            channel (str): The channel id. e.g. 'C024BE91L'

        Raises:
            SlackClientNotConnectedError: Websocket connection is closed.
        typing)rW   r]   r`   r^   Nr_   )r)   r`   rS   r*   r*   r+   ra     s   zRTMClient.typingc                 C   sj   t | dr| jn| }t| sd|}t|t| j	 }t
dd |D s3d|}t|dS )a  Checks if the specified callback is callable and accepts a kwargs param.

        Args:
            callback (obj): Any object or a list of objects that can be called.
                e.g. <function say_hello at 0x101234567>

        Raises:
            SlackClientError: The specified callback is not callable.
            SlackClientError: The callback must accept keyword arguments (**kwargs).
        r$   z,The specified callback '{}' is not callable.c                 s   s     | ]}|j |jkr|V  qd S N)kindVAR_KEYWORD).0paramr*   r*   r+   	<genexpr>7  s    z/RTMClient._validate_callback.<locals>.<genexpr>z;The callback '{}' must accept keyword arguments (**kwargs).N)hasattrr$   callableformatrX   SlackClientErrorinspect	signature
parametersvaluesany)r.   cb_namemsgcallback_paramsr*   r*   r+   r5   %  s   


zRTMClient._validate_callbackc                 C   s   |  j d7  _ | j S )zRetrieves the next message id.

        When sending messages to Slack every event should
        have a unique (for that connection) positive integer ID.

        Returns:
            An integer representing the message id. e.g. 98
           )r&   rP   r*   r*   r+   rZ   ?  s   	zRTMClient._next_msg_idc              
      s  | j sz|  jd7  _tjtj| jdd4 I dH y}|| _|  I dH \}}|j|| j	| j
| jd4 I dH G}| jd || _| jd|dI dH  |  I dH  | j su| jsu| jd	 	 W d  I dH  W d  I dH  W dS W d  I dH  n1 I dH sw   Y  W d  I dH  n1 I dH sw   Y  W nK tjtjfy } z;| jd
|dI dH  t|dr|jd
dnd}| jr| j s|dkr| |I dH  W Y d}~q| jd |    d}~ww | j rdS dS )a;  Retrieves the WS url and connects to Slack's RTM API.

        Makes an authenticated call to Slack's Web API to retrieve
        a websocket URL. Then connects to the message server and
        reads event messages as they come in.

        If 'auto_reconnect' is specified we
        retrieve a new url and reconnect any time the connection
        is lost unintentionally or an exception is thrown.

        Raises:
            SlackApiError: Unable to retrieve RTM URL from Slack.
            websockets.exceptions: Errors thrown by the 'websockets' library.
        rt   )totalr   N)	heartbeatr   r   z)The Websocket connection has been opened.openr-   dataz>Not reconnecting the Websocket because auto_reconnect is Falseerrorresponseinvalid_authz=The Websocket encountered an error. Closing the connection...)r(   r'   aiohttpClientSessionClientTimeoutr   r!   _retrieve_websocket_info
ws_connectr   r   r   r%   rN   r    _dispatch_event_read_messagesr   warningrX   rY   SlackApiErrorrh   r|   get_wait_exponentially	exceptionrO   )r)   r   urlrz   	websocketr   
error_coder*   r*   r+   rG   K  sp   *(zRTMClient._connect_and_readc              
      s  | j s| jdurz| jjddI dH }W n; tjyP   | jdu r%Y dS | jjs+Y q| jd| jj | j	d| j
 dI dH  d| _| j	ddI dH  Y dS w |jtjjkrz| }|d	d
}| j	||dI dH  W ng ty } z|r{|jn|}| jd| d| d W Y d}~qd}~ww |jtjjkr| jd| | j	d|dI dH  n(|jtjjtjjtjjfv r| jd d| _| j	ddI dH  n| jd| | j s| jdus	dS dS dS dS )z6Process messages received on the WebSocket connection.Nrt   rv   zWebsocket was closed (%s).r{   ry   closer0   r]   Unknown)rz   zCaught a raised exception (z$) while dispatching a TEXT message ()z&Received an error on the websocket: %rzWebsocket was closed.z#Received unhandled message type: %r)r(   r    receiver   TimeoutErrorclosedr%   r   
close_coder   r   r]   r~   	WSMsgTypeTEXTjsonpop	Exceptionrz   infoERRORr{   CLOSECLOSINGCLOSEDrN   )r)   messagerS   r-   errrz   r*   r*   r+   r     sZ   

	 zRTMClient._read_messagesc           	         s  | j jtjkr| j d|| | j| D ]n}| j dt| j| | z;| jr0|dvr0W  dS t	|rA|| | j
|dI dH  n| jdu rPtd|j d| | j
|d}|di | W q ty } z|j}|j}d	| d
| d| }| j |  d}~ww dS )a/  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"
                }
            }
        zReceived an event: '%s' - %sz$Running %s callbacks for event: '%s')r   r{   )
rtm_client
web_clientrz   NTzThe callback "z" 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.zWhen calling '#z()' in the 'z)' module the following error was raised: r*   )r%   levelr"   DEBUGrN   r   lenr(   rl   iscoroutinefunctionr   r   rX   SlackRequestErrorr$   r   
__module__r{   )	r)   r-   rz   r.   rS   r   r?   modulerr   r*   r*   r+   r     sF   

zRTMClient._dispatch_eventc                    s   | j du rt| j| j| j| j| jd| j| j| j	d	| _ | j
d | jdv }| jr>|r5| j  I dH }n| j  I dH }n|rF| j  }n| j  }|d}|du r]d}tj||d||jfS )	a;  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.
        NTr   zRetrieving websocket info.)z	rtm.start	rtm_startr   z&Unable to retrieve RTM URL from Slack.)r   r|   )r   r
   r   r   r   r   r   r   r!   r   r%   rN   r   r   r   rtm_connectr   rX   r   rz   )r)   use_rtm_startrespr   rr   r*   r*   r+   r     s6   




z"RTMClient._retrieve_websocket_info,  c                    sR   |j di dtd| j t  |}| jd| tt	|I dH  dS )ap  Wait exponentially longer for each connection attempt.

        Calculate the number of seconds to wait and then add
        a random number of milliseconds to avoid coincidental
        synchronized client retries. Wait up to the maximum amount
        of wait time specified via 'max_wait_time'. However,
        if Slack returned how long to wait use that.
        r   zRetry-After   z'Waiting %s seconds before reconnecting.N)
r|   r   minr'   randomr%   rN   r   sleepfloat)r)   r   max_wait_time	wait_timer*   r*   r+   r   1  s   	zRTMClient._wait_exponentiallyc                 C   sb   g }t | jdd}t|rtj| | jd}|| d| _tj| jdd| jd}|| |S )z Closes the websocket connection.r   Nr=   r0   )getattrr    ri   r   rF   r   r7   r   )r)   futuresclose_methodrK   event_fr*   r*   r+   rO   A  s   

zRTMClient._close_websocketrb   )r   )+r$   r   __qualname____doc__collectionsdefaultdictr4   r   r	   __annotations__r
   BASE_URLstrr   boolr   intr   AbstractEventLoopdictr,   staticmethodr2   classmethodr   r/   r   rL   rE   rR   rV   rT   r\   ra   r5   rZ   rG   r   r   r   r   r   rO   r*   r*   r*   r+   r      sp   
 N	

-	

A
89
4r   )r   r   r   rl   r"   r>   r   r@   r   r   r   	threadingr   r   ra   r   r   r   r	   r~   slack.errorserrorsrX   slack.web.clientr
   r   r*   r*   r*   r+   <module>   s"    