o
    >hՖ                     @   s   d dl Z d dlZd dlmZ d dlZd dlmZ d dlmZ	 d dl
mZ d dlmZmZmZ d dlmZmZ d dlmZmZ d dlmZ d	Zdd
dZdddZG dd deZG dd	 d	eZdddZdS )    N)partial)ObservableMixin)	parse_url)ComponentConfigSubscribeOptionsRegisterOptions)SessionNotReadyApplicationError)create_authenticatorIAuthenticator)SERID_TO_SER	Componentc                 C   s(  |r||  n	t | tstdt | trd| vrtd| d dvr,td| d |  D ]}|dvr=td|q0| d dkrfd	D ]}|| vrStd
|qFdD ]}|| v rctd|qVdS | d dkrdD ]}|| vr{td|qndD ]}|| v rtd|q~dS J ddS )z9
    Check a WAMP connecting endpoint configuration.
    z'endpoint' must be a dicttypez)'type' required in endpoint configuration)tcpunixzinvalid type "{}" in endpoint)r   hostportpathtlstimeoutversionz*Invalid key '{}' in endpoint configurationr   r   r   z&'{}' required in 'tcp' endpoint config)r   z''{}' not valid in 'tcp' endpoint configr   z('{}' required for 'unix' endpoint config)r   r   r   z('{}' not valid in 'unix' endpoint configFshould not arrive hereN)
isinstancedict
ValueErrorformatkeys)endpointcheck_native_endpointk r!   w/var/www/vedio/testing/chatpythonscript.ninositsolution.com/env/lib/python3.10/site-packages/autobahn/wamp/component.py_validate_endpoint1   s^   


	r#   c              
   C   s  t |tkrtdt |g d}| D ]}||vr$td|qd}d|v r?|d dvr:td|d |d }nd|d< d|v rO|dkrOtd	|dd
}|d
ur{| D ]}|dvrjtd|q]dD ]}||vrztd|qmt }d|v r|d }t|tstdt ||d}|dkr"dD ]}	|	|vrtd|	qd|vrt|d \}
}}}}}d|||
d}n	|d }t	|| d|v rtdd|v rt|d t
tfstdtdd |d D stdt }|d D ]}||vrtd|ddd |D q |dd d!g}n}|d"krd|vrh|d d#r>t|d \}}}n|d d$rSt|d \}}}}}}nt |d%krad%|d&}nd||d'}n|d }d|v rutd(|d
ur~td)d|v rt|d ttfstd*|d g}nd g}nJ d,i }d-D ]}	|	|v r||	 ||	< qt| f||dd
|||||d.|S )/a   
    Internal helper to insert defaults and create _Transport instances.

    :param transport: a (possibly valid) transport configuration
    :type transport: dict

    :returns: a _Transport instance

    :raises: ValueError on invalid configuration
    z<invalid type {} for transport configuration - must be a dict)r   urlr   
serializerserializersoptionsmax_retriesmax_retry_delayinitial_retry_delayretry_delay_growthretry_delay_jitterproxyheadersz&'{}' is not a valid configuration item	websocketr   )r/   	rawsocketzInvalid transport type {}r-   z3proxy= only supported for type=websocket transportsNr   z Unknown key '{}' in proxy configzProxy config requires '{}'r'   zoptions must be a dict, not {}r.   )r$   zTransport requires '{}' keyr   r$   r   )r   r   r   r   r%   z5'serializer' is only for rawsocket; use 'serializers'r&   z''serializers' must be a list of stringsc                 S   s   g | ]	}t |ttfqS r!   )r   str.0sr!   r!   r"   
<listcomp>   s    z%_create_transport.<locals>.<listcomp>z-Invalid serializer '{}' (expected one of: {})z, c                 S   s   g | ]}t |qS r!   )reprr2   r!   r!   r"   r5      s    cborjsonr0   rswsr   )r   r   )r   r   r   z5'serializers' is only for websocket; use 'serializer'z/'headers' not supported for rawsocket transportz'serializer' must be a stringFr   )r(   r)   r*   r+   r,   )kindr$   r   r&   r-   r'   r.   )r   r   r   r   r   getformaTr   parse_ws_urlr#   listtupleallr   join
startswithparse_rs_urlRuntimeErrorr1   
_Transport)index	transportr   valid_transport_keysr    r;   r-   r'   r.   key	is_securer   r   resourcer   paramsendpoint_configvalid_serializersserialserializer_configisSecurekwr!   r!   r"   _create_transportj   s   



	










	rT   c                   @   sR   e Zd ZdZ								dddZd	d
 Zdd Zdd Zdd Zdd Z	dS )rF   z@
    Thin-wrapper for WAMP transports used by a Connection.
    ,        ?皙?Nc                 C   s   |du rt  }|| _|| _|| _|| _|| _|| _|| _| jdkr+t|dkr+t	d|| _
|| _|| _|	| _|
| _|| _d| _|   dS )z	
        Nr0      z5'rawsocket' transport requires exactly one serializerF)r   idxr   r$   r   r'   r.   r&   lenr   r(   r)   r*   r+   r,   r-   _permanent_failurereset)selfrZ   r;   r$   r   r&   r(   r)   r*   r+   r,   r-   r'   r.   r!   r!   r"   __init__  s*   z_Transport.__init__c                 C   s   d| _ d| _d| _| j| _dS )zP
        set connection failure rates and retry-delay to initial values
        r   N)connect_attemptsconnect_sucessesconnect_failuresr*   retry_delayr^   r!   r!   r"   r]   5  s   z_Transport.resetc                 C   s
   d| _ dS )z
        Mark this transport as failed, meaning we won't try to connect to
        it any longer (that is: can_reconnect() will always return
        False afer calling this).
        TN)r\   rd   r!   r!   r"   failed>  s   
z_Transport.failedc                 C   s(   | j rdS | jdkrdS | j| jd k S )NFrU   TrY   )r\   r(   r`   rd   r!   r!   r"   can_reconnectF  s
   
z_Transport.can_reconnectc                 C   sp   | j dkrdS | jdkr| j | jd krtd| j| j | _t| j| j| j | _| j| jkr5| j| _| jS )Nr   rU   rY   zmax reconnects reached)	r`   r(   rE   rc   r+   randomnormalvariater,   r)   rd   r!   r!   r"   
next_delayM  s   
z_Transport.next_delayc                 C   s    t | jtr| jd S t| jS )zF
        returns a human-readable description of the endpoint
        r   )r   r   r   r6   rd   r!   r!   r"   describe_endpointZ  s   

z_Transport.describe_endpoint)rU   rV   rW   rW   rX   NNN)
__name__
__module____qualname____doc__r_   r]   re   rf   ri   rj   r!   r!   r!   r"   rF     s     
(	rF   c                   @   s   e Zd ZdZdZ	 dddZdddZ		d d	d
Zdd Zd!ddZ	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd ZdS )"r   z
    A WAMP application component. A component holds configuration for
    (and knows how to create) transports and sessions.
    NFc                    ,   du st tsJ  fdd}|S )a[  
        A decorator as a shortcut for subscribing during on-join

        For example::

            @component.subscribe(
                "some.topic",
                options=SubscribeOptions(match='prefix'),
            )
            def topic(*args, **kw):
                print("some.topic({}, {}): event received".format(args, kw))
        Nc                    "    fdd} d|  S )Nc                       | j  dS )N)topicr'   check_types)	subscribesessiondetails)rs   fnr'   rr   r!   r"   do_subscription     z?Component.subscribe.<locals>.decorator.<locals>.do_subscriptionrB   on)rx   ry   rs   r'   r^   rr   rx   r"   	decorator     z&Component.subscribe.<locals>.decorator)r   r   )r^   rr   r'   rs   r   r!   r}   r"   rt   r     zComponent.subscribec                    ro   )aZ  
        A decorator as a shortcut for registering during on-join

        For example::

            @component.register(
                "com.example.add",
                options=RegisterOptions(invoke='roundrobin'),
            )
            def add(*args, **kw):
                print("add({}, {}): event received".format(args, kw))
        Nc                    rp   )Nc                    rq   )N)	procedurer'   rs   )registerru   )rs   rx   r'   urir!   r"   do_registration  rz   z>Component.register.<locals>.decorator.<locals>.do_registrationrB   r{   )rx   r   rs   r'   r^   r   r~   r"   r     r   z%Component.register.<locals>.decorator)r   r   )r^   r   r'   rs   r   r!   r   r"   r     r   zComponent.registerrealm1c	                 C   s  |  g d |durt|std|| _|dur"t|s"td|| _|du r+d}t|ttfr=|}	d|	d}
|
g}nt|trE|g}g | _t	|D ]\}}
t
|
tkr\d|
d}n|
}| jt||| j qL|pmi | _|rt|| _|| _|| _d| _d| _d| _d| _dS )	a  
        :param main: After a transport has been connected and a session
            has been established and joined to a realm, this (async)
            procedure will be run until it finishes -- which signals that
            the component has run to completion. In this case, it usually
            doesn't make sense to use the ``on_*`` kwargs. If you do not
            pass a main() procedure, the session will not be closed
            (unless you arrange for .leave() to be called).

        :type main: callable taking two args ``reactor`` and ``ISession``

        :param transports: Transport configurations for creating
            transports. Each transport can be a WAMP URL, or a dict
            containing the following configuration keys:

                - ``type`` (optional): ``websocket`` (default) or ``rawsocket``
                - ``url``: the router URL
                - ``endpoint`` (optional, derived from URL if not provided):
                    - ``type``: "tcp" or "unix"
                    - ``host``, ``port``: only for TCP
                    - ``path``: only for unix
                    - ``timeout``: in seconds
                    - ``tls``: ``True`` or (under Twisted) an
                      ``twisted.internet.ssl.IOpenSSLClientComponentCreator``
                      instance (such as returned from
                      ``twisted.internet.ssl.optionsForClientTLS``) or
                      ``CertificateOptions`` instance.
                - ``max_retries``: Maximum number of reconnection attempts. Unlimited if set to -1.
                - ``initial_retry_delay``: Initial delay for reconnection attempt in seconds (Default: 1.0s).
                - ``max_retry_delay``: Maximum delay for reconnection attempts in seconds (Default: 60s).
                - ``retry_delay_growth``: The growth factor applied to the retry delay between reconnection attempts (Default 1.5).
                - ``retry_delay_jitter``: A 0-argument callable that introduces nose into the delay. (Default random.random)
                - ``serializer`` (only for raw socket): Specify an accepted serializer (e.g. 'json', 'msgpack', 'cbor', 'ubjson', 'flatbuffers')
                - ``serializers``: Specify list of accepted serializers
                - ``options``: tbd
                - ``proxy``: tbd

        :type transports: None or str or list

        :param realm: the realm to join
        :type realm: str

        :param authentication: configuration of authenticators
        :type authentication: dict

        :param session_factory: if None, ``ApplicationSession`` is
            used, otherwise a callable taking a single ``config`` argument
            that is used to create a new `ApplicationSession` instance.

        :param is_fatal: a callable taking a single argument, an
            ``Exception`` instance. The callable should return ``True`` if
            this error is "fatal", meaning we should not try connecting to
            the current transport again. The default behavior (on None) is
            to always return ``False``
        )startconnectrB   readyleave
disconnectconnectfailureNz%"is_fatal" must be a callable or Nonez""main" must be a callable if givenzws://127.0.0.1:8080/wsr/   )r   r$   F)set_valid_eventscallabler   	_is_fatal_entryr   r1   r   _transports	enumerater   appendrT   _check_native_endpoint_authenticationsession_factory_realm_extra_delay_f_done_f_session	_stopping)r^   main
transportsconfigrealmextraauthenticationr   is_fatalr$   rH   rZ   
_transportr!   r!   r"   r_     sL   9


zComponent.__init__c                 C   s   | j D ]	}| r dS qdS )NTF)r   rf   )r^   rH   r!   r!   r"   _can_reconnect  s
   
zComponent._can_reconnectc                    s   j durt fdd}tj || S t _ fdd}tj || tjdgfddfd	d
  fddd}t| j S )a  
        This starts the Component, which means it will start connecting
        (and re-connecting) to its configured transports. A Component
        runs until it is "done", which means one of:

        - There was a "main" function defined, and it completed successfully;
        - Something called ``.leave()`` on our session, and we left successfully;
        - ``.stop()`` was called, and completed successfully;
        - none of our transports were able to connect successfully (failure);

        :returns: a Future/Deferred which will resolve (to ``None``) when we are
            "done" or with an error if something went wrong.
        Nc                    s   t  |  d S N)txaioresolvearg)dr!   r"   _cb;  s   zComponent._start.<locals>._cbc                    s
   d _ | S )z}
            if the _done_f future is resolved (good or bad), we want to set it
            to None in our class
            N)r   r   rd   r!   r"   _resetE  s   z Component._start.<locals>._resetr   c                    s\   d  _  jrt jd  d S  jjdt| d  jjdt	| d t
 j|  d S )NzInternal error {msg}msg{tb}tb)r   r   r   r   r   loginfofailure_messagedebugfailure_format_tracebackreject)failrd   r!   r"   errorU  s   zComponent._start.<locals>.errorc                    sb   d _ fdd fdd fdd}fdd}tjd	 }t||| d S )
Nc                    s   j jdt| d  j jdt| d t| jtr( j jd| j	 d n7t| jt
r: j jdt| d n% | jrT| jjd d \}}} j jd	|d
 n j jdt| d  jd u rgd}n | j}|r{ j d d   tdd  d S )Nzcomponent failed: {error})r   r   r   z{msg}r   z&Connection failed with OS error: {msg}r   zTLS failure: {reason})reasonzConnection failed: {error}Fz"Error was fatal; failing transport)r   r   r   r   r   r   valuer	   r   error_messageOSErrorr   _is_ssl_errorargsr   re   
call_later)r   ssl_libssl_func
ssl_reasonr   )r^   transport_candidatetransport_checkr!   r"   handle_connect_errore  s*   
zGComponent._start.<locals>.attempt_connect.<locals>.handle_connect_errorc                    s>   t   dj}t | fdd fdd  S )Nr   c                       t  S r   r   r   _chain_fr   r!   r"   <lambda>      zYComponent._start.<locals>.attempt_connect.<locals>.notify_connect_error.<locals>.<lambda>c                    r   r   r   r   r   r!   r"   r     r   )r   create_futurefirer   add_callbacks)r   	handler_frd   r   r"   notify_connect_error  s   zGComponent._start.<locals>.attempt_connect.<locals>.notify_connect_errorc                    s   | }t |d   d S r   )r   r   )r   notify_fr   r   r!   r"   connect_error  s   z@Component._start.<locals>.attempt_connect.<locals>.connect_errorc                    s   t  jd  d S r   )r   r   r   )xrd   r!   r"   session_done  rz   z?Component._start.<locals>.attempt_connect.<locals>.session_doner   )r   r   	as_future_connect_oncer   )r   r   r   	connect_f)loopr^   r   r   r   r"   attempt_connectb  s   0z)Component._start.<locals>.attempt_connectc              
      s   j d  s1d}j | zt| ty0 } ztj| W Y d }~d S d }~ww 	 t}|	 r?|d< nq2|
 }j jd|j|j|d t|_tj  d S )NzEntering re-connect loopz:Component failed: Exhausted all transport connect attemptsTr   zZtrying transport {transport_idx} ("{transport_url}") using connect delay {transport_delay})transport_idxtransport_urltransport_delay)r   r   r   r   rE   r   r   r   nextrf   ri   warnrZ   r$   sleepr   r   )r   err_msgerH   delay)r   r   r^   r   transport_genr!   r"   r     s4   z)Component._start.<locals>.transport_checkr   )r   r   r   r   	itertoolscycler   r   )r^   r   r   r   start_fr!   )r   r   r   r   r^   r   r   r   r"   _start&  s    

N zComponent._startc                 C   sZ   d| _ | jr| j r| j S | jrttj| jS t| j	s(t
| j	d  td S )NT)r   r   is_attachedr   r   r   r   cancel	is_calledr   r   create_future_successrd   r!   r!   r"   stop  s   

zComponent.stopc                    st   j jdj d t   fdd} jd7  _tj| } fdd}t	|d |  S )NzWconnecting once using transport type "{transport_type}" over endpoint "{endpoint_desc}")transport_typeendpoint_descc            
   
      s   t jj} z,|  _}j D ]\}}t|tr$|	| qt
|fi |}|	| qW n tyK } zt|}t |  d }~ww |_ fdd}|d|  fdd}jd urp|d|  fdd}	|d	|	 |S )
Nc                    s\   j jd|d t s,|jdv rt d  d S tt|j|j}t	 | d S d S )Nz"session leaving '{details.reason}'rw   )zwamp.close.normalzwamp.close.goodbye_and_out)
r   r   r   r   r   r   create_failurer	   messager   )rv   rw   fdoner^   r!   r"   on_leave  s   

zAComponent._connect_once.<locals>.create_session.<locals>.on_leaver   c                    sf       jd7  _jjd|d tj } fdd} fdd}t||| d S )NrY   zsession on_join: {details}r   c                    s(    j d fdd}td| d S )Nmain_successc                      s$   z    W d S  ty   Y d S w r   )r   r   r!   rv   r!   r"   r   '  s
   zeComponent._connect_once.<locals>.create_session.<locals>.on_join.<locals>.main_success.<locals>.leaver   )r   r   r   r   )r   r   )r^   rv   r!   r"   r   $  s   zVComponent._connect_once.<locals>.create_session.<locals>.on_join.<locals>.main_successc                    s(   j jd| d t |    d S )Nzmain_error: {err}err)r   r   r   r   r   r   )r   r^   rv   r!   r"   
main_error0  s   zTComponent._connect_once.<locals>.create_session.<locals>.on_join.<locals>.main_error)r]   ra   r   r   r   r   r   r   )rv   rw   r   r   r   r   reactorr^   rH   r   r"   on_join  s   z@Component._connect_once.<locals>.create_session.<locals>.on_joinrB   c                    sB   j jd|d t s|sj d d S t d  d S d S )Nz,session on_disconnect: was_clean={was_clean})	was_cleanzSession disconnected uncleanly)r   r   r   r   r   r   )rv   r  r   r!   r"   on_disconnect;  s   
zFComponent._connect_once.<locals>.create_session.<locals>.on_disconnectr   )r   r   r   r   r   r   itemsr   r   add_authenticatorr
   	Exceptionr   r   r   _parentr|   r   )
cfgrv   	auth_nameauth_configauthenticatorr   r   r   r  r  r  r!   r"   create_session  s0   


z/Component._connect_once.<locals>.create_sessionrY   c                    s,    j d7  _ t st |  dS dS )a  
            this may seem redundant after looking at _connect_transport, but
            it will handle a case where something goes wrong in
            _connect_transport itself -- as the only connect our
            caller has is the 'done' future
            rY   N)rb   r   r   r   r   )r   rH   r!   r"   on_errorU  s   
z)Component._connect_once.<locals>.on_error)
r   r   r   rj   r   r   r`   r   _connect_transportr   )r^   r  rH   r  r   r  r!   r  r"   r     s   ^zComponent._connect_oncec                 C      |  d| dS )z
        A decorator as a shortcut for listening for 'join' events.

        For example::

           @component.on_join
           def joined(session, details):
               print("Session {} joined: {}".format(session, details))
        rB   Nr{   r^   rx   r!   r!   r"   r  e  s   
zComponent.on_joinc                 C   r  )zM
        A decorator as a shortcut for listening for 'leave' events.
        r   Nr{   r  r!   r!   r"   r   q     zComponent.on_leavec                 C   r  )zO
        A decorator as a shortcut for listening for 'connect' events.
        r   Nr{   r  r!   r!   r"   
on_connectw  r  zComponent.on_connectc                 C   r  )zR
        A decorator as a shortcut for listening for 'disconnect' events.
        r   Nr{   r  r!   r!   r"   r  }  r  zComponent.on_disconnectc                 C   r  )zM
        A decorator as a shortcut for listening for 'ready' events.
        r   Nr{   r  r!   r!   r"   on_ready  r  zComponent.on_readyc                 C   r  )zV
        A decorator as a shortcut for listening for 'connectfailure' events.
        r   Nr{   r  r!   r!   r"   on_connectfailure  r  zComponent.on_connectfailure)NF)NNNr   NNNNr   )rk   rl   rm   rn   r   rt   r   r_   r   r   r   r   r  r   r  r  r  r  r!   r!   r!   r"   r   g  s*    



 / c           
         s   t |tr|g}t|tkrtdt||D ]}t |ts)tdt|qt fddfdd  fdd}g }|D ]}||}|| qFtj	|d	d
}rjfdd}	t
||	|	 |S )a  
    Internal helper. Use "run" method from autobahn.twisted.wamp or
    autobahn.asyncio.wamp

    This is the generic parts of the run() method so that there's very
    little code in the twisted/asyncio specific run() methods.

    This is called by react() (or run_until_complete() so any errors
    coming out of this should be handled properly. Logging will
    already be started.
    zB"components" must be a list of Component objects - encountered {0}zN"components" must be a list of Component objects - encountereditem of type {0}c                    s    j d| |d |S )Nz-Component '{c}' successfully completed: {arg})cr   r   )compr   r   r!   r"   component_success  s   z_run.<locals>.component_successc                    s.    j d| t|d  jdt|d d S )NzComponent '{c}' error: {msg})r  r   zComponent error: {tb}r   )r   r   r   r   r   )r  r   r  r!   r"   component_failure  s   z_run.<locals>.component_failurec                    s,   t | j}t |t| t |  |S r   )r   r   r   r   r   )r  r   )r  r  r  r!   r"   component_start  s   z_run.<locals>.component_startF)consume_exceptionsc                    s    d  |  d S )Nz&All components ended; stopping reactorr  r   )done_callbackr   r  r!   r"   all_done  s   
z_run.<locals>.all_done)r   r   r   r?   r   r   r   make_loggerr   gatherr   )
r  
componentsr  r  r  dlr  r   done_dr   r!   )r  r  r  r   r  r"   _run  s6   



r&  r   )r   rg   	functoolsr   r   autobahn.utilr   autobahn.websocket.utilr   r>   autobahn.rawsocket.utilrD   autobahn.wamp.typesr   r   r   autobahn.wamp.exceptionr   r	   autobahn.wamp.authr
   r   autobahn.wamp.serializerr   __all__r#   rT   objectrF   r   r&  r!   r!   r!   r"   <module>   s.   

9 _    -