o
    @Bi?                     @   s   d dl mZ d dlZ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 Z!dS )    )absolute_importN)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tlsz*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/html/Trade-python/venv/lib/python3.10/site-packages/autobahn/wamp/component.py_validate_endpoint4   s^   


	r"   c              	   C   sn  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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}nu|d!krd|vrb|d d"r8t|d \}}
}n|d d#rMt|d \}}
}}}}nt |
d$kr[d$|d%}nd|
|d&}n|d }d|v rotd'd|v rt|d tj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proxyz&'{}' 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#   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jtfqS r    )r   six	text_type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jsonr.   rswsr   )r   r   )r   r   r   z5'serializers' is only for websocket; use 'serializer'z'serializer' must be a stringFr   )r'   r(   r)   r*   r+   )kindr#   r   r%   r,   r&   )r   r   r   r   r   getformaTr   parse_ws_urlr"   listtupleallr   join
startswithparse_rs_urlRuntimeErrorr/   r0   r1   
_Transport)index	transportr   valid_transport_keysr   r;   r,   r&   key	is_securer   r   resourcer   paramsendpoint_configvalid_serializersserialserializer_configisSecurekwr    r    r!   _create_transportm   s   


	









rT   c                   @   sR   e Zd ZdZdddddde f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.
    i,  g      ?g?Nc                 C   sx   || _ || _|| _|| _|| _|| _| jdkr!t|dkr!td|| _|| _	|| _
|	| _|
| _|| _d| _|   dS )z	
        r.      z5'rawsocket' transport requires exactly one serializerFN)idxr   r#   r   r&   r%   lenr   r'   r(   r)   r*   r+   r,   _permanent_failurereset)selfrW   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!   rZ   /  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)rY   ra   r    r    r!   failed8  s   
z_Transport.failedc                 C   s(   | j rdS | jdkrdS | j| jd k S )NFrU   TrV   )rY   r'   r]   ra   r    r    r!   can_reconnect@  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   rV   zmax reconnects reached)	r]   r'   rE   r`   r*   randomnormalvariater+   r(   ra   r    r    r!   
next_delayG  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   ra   r    r    r!   describe_endpointT  s   

z_Transport.describe_endpoint)__name__
__module____qualname____doc__r   r\   rZ   rb   rc   rf   rg   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.
    Nc                    *    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(
                u"some.topic",
                options=SubscribeOptions(match=u'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&   )	subscribesessiondetails)fnr&   ro   r    r!   do_subscription}     z?Component.subscribe.<locals>.decorator.<locals>.do_subscriptionrB   on)rt   ru   r&   r[   ro   rt   r!   	decorator{     z&Component.subscribe.<locals>.decorator)r   r   )r[   ro   r&   r{   r    ry   r!   rp   l     zComponent.subscribec                    rl   )a\  
        A decorator as a shortcut for registering during on-join

        For example::

            @component.register(
                u"com.example.add",
                options=RegisterOptions(invoke='round_robin'),
            )
            def add(*args, **kw):
                print("add({}, {}): event received".format(args, kw))
        Nc                    rm   )Nc                    rn   )N)	procedurer&   )registerrq   )rt   r&   urir    r!   do_registration  rv   z>Component.register.<locals>.decorator.<locals>.do_registrationrB   rw   )rt   r   r&   r[   r   rz   r!   r{     r|   z%Component.register.<locals>.decorator)r   r   )r[   r   r&   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jtfr>|}	d|	d}
|
g}nt|t	rF|g}g | _
t|D ]\}}
| j
t||
| j qM|p`i | _|rg|| _|| _|| _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 2 args: reactor, 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 unicode or list of dicts

        :param realm: the realm to join
        :type realm: unicode

        :param authentication: configuration of authenticators
        :type authentication: dict mapping auth_type to 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.
        :type session_factory: callable

        :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``
        :type is_fatal: callable taking one arg, or None
        )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   r/   r0   r1   r   _transports	enumerate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   rW   r    r    r!   r\     sB   ;


zComponent.__init__c                 C   s   | j D ]	}| r dS qdS )NTF)r   rc   )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/  rv   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   ra   r    r!   _reset9  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)failra   r    r!   errorI  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: {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   rb   
call_later)r   ssl_libssl_func
ssl_reasonr   )r[   transport_candidatetransport_checkr    r!   handle_connect_errorY  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_fra   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   )xra   r    r!   session_done  s   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_connectV  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|d t|_tj  d S )NzEntering re-connect loopz:Component failed: Exhausted all transport connect attemptsTr   zFtrying transport {transport_idx} using connect delay {transport_delay})transport_idxtransport_delay)r   r   r   r   rE   r   r   r   nextrc   rf   rW   sleepr   r   )r   err_msgerH   delay)r   r   r[   r   transport_genr    r!   r     s2   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_successra   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                    sX   j jd|d t s*|jdv rt d  d S tt|j}t | d S d S )Nz"session leaving '{details.reason}'rs   )zwamp.close.normal)	r   r   r   r   r   r   create_failurer
   r   )rr   rs   fdoner[   r    r!   on_leave  s   

zAComponent._connect_once.<locals>.create_session.<locals>.on_leaver   c                    s^    j d7  _ jjd|d tj } fdd} fdd}t||| d S )NrV   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    rr   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[   rr   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[   rr   r    r!   
main_error"  s   zTComponent._connect_once.<locals>.create_session.<locals>.on_join.<locals>.main_error)r^   r   r   r   r   r   r   )rr   rs   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   warnr   )rr   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   _parentrx   r   )
cfgrr   	auth_nameauth_configauthenticatorr   r   r   r   r   r   r    r!   create_session  s0   


z/Component._connect_once.<locals>.create_sessionrV   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
            rV   N)r_   r   r   r   r   )r   rH   r    r!   on_errorG  s   
z)Component._connect_once.<locals>.on_error)
r   r   r   rg   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   Nrw   r[   rt   r    r    r!   r   W  s   
zComponent.on_joinc                 C   r
  )zM
        A decorator as a shortcut for listening for 'leave' events.
        r   Nrw   r  r    r    r!   r   c     zComponent.on_leavec                 C   r
  )zO
        A decorator as a shortcut for listening for 'connect' events.
        r   Nrw   r  r    r    r!   
on_connecti  r  zComponent.on_connectc                 C   r
  )zR
        A decorator as a shortcut for listening for 'disconnect' events.
        r   Nrw   r  r    r    r!   r   o  r  zComponent.on_disconnectc                 C   r
  )zM
        A decorator as a shortcut for listening for 'ready' events.
        r   Nrw   r  r    r    r!   on_readyu  r  zComponent.on_readyc                 C   r
  )zV
        A decorator as a shortcut for listening for 'connectfailure' events.
        r   Nrw   r  r    r    r!   on_connectfailure{  r  zComponent.on_connectfailurer   )NNNr   NNNN)rh   ri   rj   rk   r   rp   r   r\   r   r   r   r   r   r   r  r   r  r  r    r    r    r!   r   a  s*    


y
 . 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
}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  s4   



r  r   )"
__future__r   r   r/   rd   	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>   s2   

9 [    %