a
    ߙfb                     @   s  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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 ddlmZ ddlmZmZmZ ddlmZmZmZ dd	lmZmZ dd
lmZ ddl m!Z!m"Z" ddgZ#ddgZ$G dd dZ%G dd dZ&dS )    N)
urlunparse)log   )SAMP_STATUS_OK)__profile_version__)SAMPWarningSAMPHubErrorSAMPProxyError)internet_onServerProxyPool_HubAsClient)read_lockfilecreate_lock_file)ThreadingXMLRPCServer)WebProfileXMLRPCServerweb_profile_text_dialogSAMPHubServerWebProfileDialog.zSAMPHubServer.*c                   @   s  e Zd ZdZdd	d
Zedd Zdd Zdd Zdd Z	dd Z
dddZdddZdd Zdd Zdd Zdd  Zdd"d#Zed$d% Zd&d' Zd(d) Zd*d+ Zdd,d-Zed.d/ Zd0d1 Zd2d3 Zd4d5 Zd6d7 Zd8d9 Zd:d; Zd<d= Zd>d? Zd@dA Z dBdC Z!dDdE Z"dFdG Z#dHdI Z$dJdK Z%dLdM Z&dNdO Z'dPdQ Z(dRdS Z)dTdU Z*dVdW Z+e,dXdY Z-dZd[ Z.d\d] Z/d^d_ Z0d`da Z1dbdc Z2ddde Z3dfdg Z4dhdi Z5djdk Z6dldm Z7dndo Z8dpdq Z9drds Z:dtdu Z;dvdw Z<ddxdyZ=dzd{ Z>d|d} Z?d~d Z@dddZAdd ZBdd ZCdS )r   a
  
    SAMP Hub Server.

    Parameters
    ----------
    secret : str, optional
        The secret code to use for the SAMP lockfile. If none is is specified,
        the :func:`uuid.uuid1` function is used to generate one.

    addr : str, optional
        Listening address (or IP). This defaults to 127.0.0.1 if the internet
        is not reachable, otherwise it defaults to the host name.

    port : int, optional
        Listening XML-RPC server socket port. If left set to 0 (the default),
        the operating system will select a free port.

    lockfile : str, optional
        Custom lockfile name.

    timeout : int, optional
        Hub inactivity timeout. If ``timeout > 0`` then the Hub automatically
        stops after an inactivity period longer than ``timeout`` seconds. By
        default ``timeout`` is set to 0 (Hub never expires).

    client_timeout : int, optional
        Client inactivity timeout. If ``client_timeout > 0`` then the Hub
        automatically unregisters the clients which result inactive for a
        period longer than ``client_timeout`` seconds. By default
        ``client_timeout`` is set to 0 (clients never expire).

    mode : str, optional
        Defines the Hub running mode. If ``mode`` is ``'single'`` then the Hub
        runs using the standard ``.samp`` lock-file, having a single instance
        for user desktop session. Otherwise, if ``mode`` is ``'multiple'``,
        then the Hub runs using a non-standard lock-file, placed in
        ``.samp-1`` directory, of the form ``samp-hub-<UUID>``, where
        ``<UUID>`` is a unique UUID assigned to the hub.

    label : str, optional
        A string used to label the Hub with a human readable name. This string
        is written in the lock-file assigned to the ``hub.label`` token.

    web_profile : bool, optional
        Enables or disables the Web Profile support.

    web_profile_dialog : class, optional
        Allows a class instance to be specified using ``web_profile_dialog``
        to replace the terminal-based message with e.g. a GUI pop-up. Two
        `queue.Queue` instances will be added to the instance as attributes
        ``queue_request`` and ``queue_result``. When a request is received via
        the ``queue_request`` queue, the pop-up should be displayed, and a
        value of `True` or `False` should be added to ``queue_result``
        depending on whether the user accepted or refused the connection.

    web_port : int, optional
        The port to use for web SAMP. This should not be changed except for
        testing purposes, since web SAMP should always use port 21012.

    pool_size : int, optional
        The number of socket connections opened to communicate with the
        clients.
    Nr   single TR     c                 C   sB  t t | _d| _|| _d | _|| _|| _|| _	|| _
|| _|| _|| _|	| _|
| _|| _d | _i | _d | _d | _d | _d| _t rz(t | _t| jp| j| jpd W n tjy   d| _Y n0 t | _d | _d | _ d | _!g | _"d | _#i | _$d| _%|| _&| ' | _(d| _)i | _*i | _+i | _,i | _-i | _.i | _/d| _0d S )NF	127.0.0.1r   r   )1struuiduuid1_id_is_running_customlockfilename	_lockfile_addr_port_mode_label_timeout_client_timeout
_pool_size_web_profile_web_profile_dialog	_web_port_web_profile_server_web_profile_callbacks_web_profile_requests_queue_web_profile_requests_result_web_profile_requests_semaphore
_host_namer
   socketZgetfqdnZgetaddrinfoerror	threadingZLock_thread_lock_thread_run_thread_hub_timeout_thread_client_timeout_launched_threads_last_activity_time_client_activity_time_hub_msg_id_counter_hub_secret_code_customized_create_secret_code_hub_secret_hub_public_id_private_keys	_metadata
_mtype2ids
_id2mtypes_xmlrpc_endpoints_sync_msg_ids_heap_client_id_counter)selfsecretaddrZportZlockfiletimeoutZclient_timeoutmodeZlabelweb_profileZweb_profile_dialogZweb_portZ	pool_size rN   /lib/python3.9/site-packages/astropy/samp/hub.py__init__b   s\    


zSAMPHubServer.__init__c                 C   s   | j S )z$
        The unique hub ID.
        )r   rH   rN   rN   rO   id   s    zSAMPHubServer.idc                 C   s   | | jd | | jd | | jd | | jd | | jd | | jd | | jd | | jd | | j	d	 | | j
d
 | | jd | | jd | | jd | | jd | | jd | | jd d S )Nzsamp.hub.pingzsamp.hub.setXmlrpcCallbackzsamp.hub.registerzsamp.hub.unregisterzsamp.hub.declareMetadatazsamp.hub.getMetadatazsamp.hub.declareSubscriptionszsamp.hub.getSubscriptionszsamp.hub.getRegisteredClientszsamp.hub.getSubscribedClientszsamp.hub.notifyzsamp.hub.notifyAllzsamp.hub.callzsamp.hub.callAllzsamp.hub.callAndWaitzsamp.hub.reply)register_function_ping_set_xmlrpc_callback	_register_unregister_declare_metadata_get_metadata_declare_subscriptions_get_subscriptions_get_registered_clients_get_subscribed_clients_notify_notify_all_call	_call_all_call_and_wait_replyrH   ZserverrN   rN   rO   _register_standard_api   s     z$SAMPHubServer._register_standard_apic                 C   s   | | jd | | jd | | jd | | jd | | jd | | jd | | jd | | jd | | j	d	 | | j
d
 | | jd | | jd | | jd | | jd | | jd | | jd | | jd d S )Nzsamp.webhub.pingzsamp.webhub.unregisterzsamp.webhub.declareMetadatazsamp.webhub.getMetadataz samp.webhub.declareSubscriptionszsamp.webhub.getSubscriptionsz samp.webhub.getRegisteredClientsz samp.webhub.getSubscribedClientszsamp.webhub.notifyzsamp.webhub.notifyAllzsamp.webhub.callzsamp.webhub.callAllzsamp.webhub.callAndWaitzsamp.webhub.replyzsamp.webhub.registerz!samp.webhub.allowReverseCallbackszsamp.webhub.pullCallbacks)rS   rT   rW   rX   rY   rZ   r[   r\   r]   r^   r_   r`   ra   rb   rc   _web_profile_register"_web_profile_allowReverseCallbacks_web_profile_pullCallbacksrd   rN   rN   rO   _register_web_profile_api   s"    z'SAMPHubServer._register_web_profile_apic                 C   s   t | jp| j| jpdftddd| _d}| jj d | _| jpD| j d| j }t||ddddf| _	| j
  | | j d S )	Nr   FTZlogRequests
allow_noneZhttpr   :r   )r   r"   r1   r#   r   _serverr2   getsocknamer   _url register_introspection_functionsre   )rH   ZprotrJ   rN   rN   rO   _start_standard_server   s    
z$SAMPHubServer._start_standard_serverc                 C   s   t d| _t d| _t d| _| jd urB| j| j_| j| j_zNtd| j	ft
ddd| _| jj d | _	| j  | | j t
d W n@ tjy   t
d| j	t d| _d | _d | _d | _Y n0 d S )Nr   	localhostFTrj   z0Hub set to run with Web Profile support enabled.zKPort {} already in use. Impossible to run the Hub with Web Profile support.)queueQueuer.   r/   r0   r*   queue_requestqueue_resultr   r+   r   r,   r2   rn   rp   ri   infor3   Zwarningformatr   r)   rQ   rN   rN   rO   _start_web_profile_server   s6    

z'SAMPHubServer._start_web_profile_serverc                 C   sb   g }| j D ]}| s
|| q
|D ]}| j | q&tj||||d}|  | j | d S )N)grouptargetnameargs)r9   is_aliveappendremover4   Threadstart)rH   rz   r{   r|   r}   r   trN   rN   rO   _launch_thread  s    
zSAMPHubServer._launch_threadc                 C   s   | j D ]}|j|d qd S NrK   )r9   join)rH   rK   r   rN   rN   rO   _join_launched_threads(  s    
z$SAMPHubServer._join_launched_threadsc                 C   s   | j dkrd S t }| jrtd t }|| dkr| jN | jd ur|| j | j krtdt | 	  W d    d S W d    n1 s0    Y  |}qd S )Nr   皙?      ?z&Timeout expired, Hub is shutting down!)
r&   timer   sleepr5   r:   warningswarnr   stop)rH   lastnowrN   rN   rO   _timeout_test_hub,  s     


.zSAMPHubServer._timeout_test_hubc                 C   s   | j dkrd S t }| jrtd t }|| dkr| j D ]J}|| j|  | j krD|| jkrDtd| dt	 | 
| | | qD|}qd S )Nr   r   r   zClient z timeout expired!)r'   r   r   r   r;   keys_hub_private_keyr   r   r   _notify_disconnectionrW   )rH   r   r   private_keyrN   rN   rO   _timeout_test_client?  s$    



z"SAMPHubServer._timeout_test_clientc                 C   sL   |dkr| j | S |dkr$| j| S |dkr6| j| S |dkrH| j| S d S )Nzsamp.client.receiveCallzsamp.client.receiveNotificationzsamp.client.receiveResponsesamp.app.ping)_receive_call_receive_notification_receive_responserT   )rH   methodr}   rN   rN   rO   _hub_as_client_request_handlerS  s    


z,SAMPHubServer._hub_as_client_request_handlerc                 C   sn   d| j dd| jd d}| | j}|d | _|d | _| | j| j | | j| | | ji i d d S )	NzAstropy SAMP HubzThe Astropy Collaborationz'https://docs.astropy.org/en/stable/sampz
/samp/icon)	samp.namezsamp.description.textzauthor.namezsamp.documentation.urlzsamp.icon.urlsamp.self-idsamp.private-key)r   x-samp.query.by-meta)	r%   ro   rV   r?   r@   r   rU   rX   rZ   )rH   Zhub_metadataresultrN   rN   rO   _setup_hub_as_client]  s     

z"SAMPHubServer._setup_hub_as_clientFc                 C   s   | j rtd| jdur td| jr.|   |   t| j| j| j	| j
d| _|   |   |   td |r| j r| j  d| _dS )a<  
        Start the current SAMP Hub instance and create the lock file. Hub
        start-up can be blocking or non blocking depending on the ``wait``
        parameter.

        Parameters
        ----------
        wait : bool
            If `True` then the Hub process is joined with the caller, blocking
            the code flow. Usually `True` option is used to run a stand-alone
            Hub in an executable script. If `False` (default), then the Hub
            process runs in a separated thread. `False` is usually used in a
            Python shell.
        zHub is already runningNz&Hub is not running but lockfile is set)ZlockfilenamerL   Zhub_idZ
hub_paramszHub started)r   r   r!   r)   ry   rq   r   r    r$   rR   params_update_last_activity_timer   _start_threadsr   rw   r6   r   )rH   waitrN   rN   rO   r   n  s$    



zSAMPHubServer.startc                 C   sD   i }| j |d< | j|d< t|d< | j|d< | jp:d| j |d< |S )zG
        The hub parameters (which are written to the logfile)
        samp.secretzsamp.hub.xmlrpc.urlzsamp.profile.versionzhub.idzHub z	hub.label)r?   ro   r   rR   r%   )rH   r   rN   rN   rO   r     s    


zSAMPHubServer.paramsc                 C   s   t j| jd| _d| j_| jdkr>t j| jdd| _d| j_nd | _| jdkrjt j| j	dd| _
d| j
_nd | _
d| _| j  | jd ur| j  | j
d ur| j
  d S )N)r{   Tr   zHub timeout test)r{   r|   zClient timeout test)r4   r   _serve_foreverr6   Zdaemonr&   r   r7   r'   r   r8   r   r   rQ   rN   rN   rO   r     s,    







zSAMPHubServer._start_threadsc                 C   s    | j d ur| j S tt S d S N)r=   r   r   r   rQ   rN   rN   rO   r>     s    
z!SAMPHubServer._create_secret_codec                 C   s   | j s
dS td |   d| _ | jrZtj| jrZt| j}|d | j	krZt
| j d| _| jdd d| _|  | _	d| _i | _i | _i | _i | _i | _d| _td	 dS )
zN
        Stop the current SAMP Hub instance and delete the lock file.
        NzHub is stopping...Fr   g      $@r   r   r   zHub stopped.)r   r   rw   _notify_shutdownr!   ospathisfiler   r?   r   _join_all_threadsr<   r>   r@   rB   rA   rC   rD   rE   r:   )rH   ZlockfiledictrN   rN   rO   r     s*    


zSAMPHubServer.stopc                 C   s   t  }| j|ur0| jj|d | j s0d | _| jd urb| j|urb| jj|d | j sbd | _| jd ur| j|ur| jj|d | j sd | _| j|d d S r   )r4   current_threadr6   r   r~   r7   r8   r   )rH   rK   r   rN   rN   rO   r     s    



zSAMPHubServer._join_all_threadsc                 C   s   | j S )zReturn an information concerning the Hub running status.

        Returns
        -------
        running : bool
            Is the hub running?
        )r   rQ   rN   rN   rO   
is_running  s    	zSAMPHubServer.is_runningc              
   C   s8  | j rzt| jjgg g dd }W n6 ty\ } ztd| t W Y d }~nd }~0 0 |rl| j  | j	r | j
d u rz| j }W n tjy   Y n0 t|| j zt| jjgg g dd }W n8 ty } ztd| t W Y d }~q d }~0 0 |r | j  q | j  | jd ur4| j  d S )N{Gz?r   z*Call to select() in SAMPHubServer failed: )r   selectrm   r2   OSErrorr   r   r   Zhandle_requestr)   r*   r.   
get_nowaitrs   Emptyr   r/   r,   Zserver_close)rH   Z
read_readyexcrequestrN   rN   rO   r     s6    


zSAMPHubServer._serve_foreverc              	   C   sR   t d}|D ]>}|| jv r| j| D ]$}| | j| j| d di d q&qd S )Nzsamp.hub.event.shutdownr   
samp.mtypesamp.params)r   get_mtype_subtypesrC   _notify_r   rA   )rH   msubsmtypekeyrN   rN   rO   r   :  s    

zSAMPHubServer._notify_shutdownc              	   C   sd   t d}|D ]P}|| jv r| j| d }| j| D ](}| | j| j| d dd|id q4qd S )Nzsamp.hub.event.registerr   rR   r   r   r   rC   rA   r^   r   rH   r   r   r   	public_idr   rN   rN   rO   _notify_registerD  s    

zSAMPHubServer._notify_registerc              	   C   sl   t d}|D ]X}|| jv r| j| d }| j| D ]0}||kr4| | j| j| d dd|id q4qd S )Nzsamp.hub.event.unregisterr   rR   r   r   r   rN   rN   rO   _notify_unregisterP  s    

z SAMPHubServer._notify_unregisterc              
   C   sl   t d}|D ]X}|| jv r| j| d }| j| D ]0}| | j| j| d d|| j| dd q4qd S )Nzsamp.hub.event.metadatar   )rR   metadatar   )r   r   rC   rA   r^   r   rB   r   rN   rN   rO   _notify_metadata\  s    

zSAMPHubServer._notify_metadatac              
   C   sl   t d}|D ]X}|| jv r| j| d }| j| D ]0}| | j| j| d d|| j| dd q4qd S )Nzsamp.hub.event.subscriptionsr   )rR   Zsubscriptionsr   )r   r   rC   rA   r^   r   rD   r   rN   rN   rO   _notify_subscriptionsj  s    

z#SAMPHubServer._notify_subscriptionsc              	   C   s   dd }t d}| j| d }| j| d }|D ]N}|| jv r2|| j| v r2td|  | j|||| jdddid	fd
 q2d S )Nc                 S   s   | j j||| d S r   )sampclientreceiveNotification)endpointr   hub_public_idmessagerN   rN   rO   _xmlrpc_call_disconnecty  s    zDSAMPHubServer._notify_disconnection.<locals>._xmlrpc_call_disconnectzsamp.hub.disconnectr   r   znotify disconnection to reasonTimeout expired!r   r{   r}   )	r   r   rA   rE   rC   r   debugr   r@   )rH   r   r   r   r   r   r   rN   rN   rO   r   w  s    
z#SAMPHubServer._notify_disconnectionc                 C   s   |    td dS )NZping1)r   r   r   rQ   rN   rN   rO   rT     s    
zSAMPHubServer._pingc                 C   sH   g }| j D ]8}|| j | v r
| j | | |kr
|| j| d  q
|S Nr   )rB   r   rA   )rH   r   valueZpublic_id_listZ
private_idrN   rN   rO   _query_by_metadata  s    
z SAMPHubServer._query_by_metadatac                 C   s   |  | || jv r|| jkrD| j| d }|t| jf| j|< dS td| d|  d }t| j	t
j|dd}| j| d }||f| j|< ntdd| d	dS )
Nr   r   zset_xmlrpc_callback:  r   )rk      Private-key  expired or invalid.)r   rA   r   r   r   rE   r   r   r   r(   xmlrpcZServerProxyr	   )rH   r   Zxmlrpc_addrr   Zserver_proxy_poolrN   rN   rO   rU     s&    


z"SAMPHubServer._set_xmlrpc_callbackc                 C   s|   | j  |  \}}W d    n1 s(0    Y  |t f| j|< | | | | td| d|  ||| jdS )Nzregister: private-key = z and self-id = )r   r   zsamp.hub-id)	r5   _get_new_idsr   rA   r   r   r   r   r@   rH   r   r   rN   rN   rO   _perform_standard_register  s    *

z(SAMPHubServer._perform_standard_registerc                 C   s(   |    || jkr|  S tddd S )N   zBad secret code)r   r?   r   r	   )rH   rI   rN   rN   rO   rV     s    
zSAMPHubServer._registerc                 C   s<   t t }|  jd7  _d}| jdkr4d| j }||fS )Nr   zcli#hubr   zcli#)r   r   r   rG   r   rN   rN   rO   r     s    
zSAMPHubServer._get_new_idsc                 C   s$  |    d}| | | j || jv r@| j| d }| j|= nW d    dS || jv rb| j|= || jv rt| j|= | j D ]"}|| j| v r~| j| | q~|| j	v r| j	|= || j
v r| j
|= | jr|| jv r| j|= | j| W d    n1 s0    Y  td| d| d dS )Nr   r   zunregister z ())r   r   r5   rA   rB   rD   rC   r   r   rE   r;   r)   r-   r,   Zremove_clientr   r   )rH   r   Z
public_keyr   rN   rN   rO   rW     s2    







*zSAMPHubServer._unregisterc                 C   sV   |  | || jv r@td|t| || j|< | | ntdd| ddS )Nz0declare_metadata: private-key = {} metadata = {}r   r   r   r   )	r   rA   r   r   rx   r   rB   r   r	   )rH   r   r   rN   rN   rO   rX     s    


zSAMPHubServer._declare_metadatac                 C   s   |  | || jv rt| |}td|| |d urh|| jv rbtd| j|   | j| S i S qtddntdd| dd S )Nz-get_metadata: private-key = {} client-id = {}z--> metadata =    Invalid client IDr   r   r   )r   rA   _public_id_to_private_keyr   r   rx   rB   r	   rH   r   Z	client_idZclient_private_keyrN   rN   rO   rY     s    




zSAMPHubServer._get_metadatac              	   C   sN  |  | || jv r8td|t| || jv rr| j| }|D ],}z| j| | W qD t	yn   Y qD0 qDt
|| j|< t
|}|D ]@}|dr|D ],}||d d r||kr||v r||= qqtd|t| |D ]>}|| jv r|| j| vr*| j| | q|g| j|< q| | ntdd| ddS )	Nz3declare_subscriptions: private-key = {} mtypes = {}*r   z;declare_subscriptions: subscriptions accepted from {} => {}r   r   r   r   )r   rA   r   r   rx   r   rD   rC   r   
ValueErrorcopydeepcopyendswith
startswithr   r   r	   )rH   r   ZmtypesZprev_mtypesr   Zoriginal_mtypesZmtype2rN   rN   rO   rZ     sB    





z$SAMPHubServer._declare_subscriptionsc                 C   s   |  | || jv rx| |}|d url|| jv rVtd|t| j|  | j| S td| i S qtddntdd| dd S )Nz-get_subscriptions: client-id = {} mtypes = {}z2get_subscriptions: client-id = {} mtypes = missingr   r   r   r   r   )	r   rA   r   rD   r   r   rx   r   r	   r   rN   rN   rO   r[   G  s     




z SAMPHubServer._get_subscriptionsc                 C   sp   |  | || jv rZg }| j D ] }||kr"|| j| d  q"td|| |S tdd| dd S )Nr   z5get_registered_clients: private_key = {} clients = {}r   r   r   )r   rA   r   r   r   r   rx   r	   )rH   r   Zreg_clientspkeyrN   rN   rO   r\   \  s    

z%SAMPHubServer._get_registered_clientsc                 C   s|   |  | || jv rfi }| j D ]*}||kr"| ||r"i || j| d < q"td||| |S tdd| dd S )Nr   z@get_subscribed_clients: private_key = {} mtype = {} clients = {}r   r   r   )r   rA   r   _is_subscribedr   r   rx   r	   )rH   r   r   Zsub_clientsr   rN   rN   rO   r]   k  s    

z%SAMPHubServer._get_subscribed_clientsc                 C   s|   g }|  d}ttt|}|  |d |D ]B}d|d|d  }|| krl|dkrh|d }nd}|| q4|S )a  
        Return a list containing all the possible wildcarded subtypes of MType.

        Parameters
        ----------
        mtype : str
            MType to be parsed.

        Returns
        -------
        types : list
            List of subtypes

        Examples
        --------
        >>> from astropy.samp import SAMPHubServer
        >>> SAMPHubServer.get_mtype_subtypes("samp.app.ping")
        ['samp.app.ping', 'samp.app.*', 'samp.*', '*']
        r   r   Nr   r   z.*r   )splitlistrangelenreverser   r   )r   Zsubtypesr   ZindexesiZ	tmp_mtyperN   rN   rO   r   |  s    


z SAMPHubServer.get_mtype_subtypesc                 C   s8   d}t |}|D ] }|| jv r|| j| v rd}q|S )NFT)r   r   rC   )rH   r   r   Z
subscribedr   ZmsubrN   rN   rO   r     s    

zSAMPHubServer._is_subscribedc                 C   st   |  | || jv r^| | ||d du rDtdd||d | j| j|||fd i S tdd| dd S )	Nr   F   $Client {} not subscribed to MType {}r   r   r   r   )r   rA   r   r   r	   rx   r   r   )rH   r   recipient_idr   rN   rN   rO   r^     s     


zSAMPHubServer._notifyc           	      C   s   || j vrd S | j | d }zBtd|d || | |}||f}d}| |||| W n@ ty } z(td|d |||t	 W Y d }~n
d }~0 0 d S )Nr   znotify {} from {} to {}r   r   z7{} notification from client {} to client {} failed [{}])
rA   r   r   rx   r   _retry_method	Exceptionr   r   r   )	rH   sender_private_keyrecipient_public_idr   sender_public_idrecipient_private_key
arg_paramssamp_method_namer   rN   rN   rO   r     s(    

zSAMPHubServer._notify_c                 C   sL   |  | || jv r6d|vr&tdd| ||}|S tdd| dd S )Nr      zsamp.mtype keyword is missingr   r   r   )r   rA   r	   _notify_all_)rH   r   r   recipient_idsrN   rN   rO   r_     s    


zSAMPHubServer._notify_allc                 C   sp   g }t |d }|D ]T}|| jv r| j| D ]:}||kr.| j| d }|| | j| j|||fd q.q|S Nr   r   r   )r   r   rC   rA   r   r   r^   )rH   r   r   r  r   r   r   Z_recipient_idrN   rN   rO   r     s    


zSAMPHubServer._notify_all_c                 C   s   |  | || jv r|| | ||d du rDtdd||d | j| d }| ||}| j| j|||||fd |S tdd| d	d S )
Nr   Fr   r   r   r   r   r   r   )	r   rA   r   r   r	   rx   _get_new_hub_msg_idr   _call_)rH   r   r   msg_tagr   r   msg_idrN   rN   rO   r`     s$    

zSAMPHubServer._callc           
      C   s   || j vrd S zPtd|dd |||d  | |}|||f}d}| |||| W nR ty }	 z:t	d|d |dd ||t
|	|	t W Y d }	~	n
d }	~	0 0 d S )Nzcall {} from {} to {} ({});;r   r   ZreceiveCallz5{} call {} from client {} to client {} failed [{},{}])rA   r   r   rx   r   r   r   r   r   r   typer   )
rH   r   r   r   r  r   r   r   Zsamp_methodNamer   rN   rN   rO   r  	  s(    



zSAMPHubServer._call_c                 C   sd   |  | || jv rNd|vr,tdd|| j| d }| ||||}|S tdd| dd S )Nr   r   z5samp.mtype keyword is missing in message tagged as {}r   r   r   r   )r   rA   r	   rx   
_call_all_)rH   r   r  r   r   r  rN   rN   rO   ra   #  s    

zSAMPHubServer._call_allc              	   C   s~   i }t |d }|D ]b}|| jv r| j| D ]H}||kr.| ||}	| j| d }
|	||
< | j| j|||
|	|fd q.q|S r  )r   r   rC   r  rA   r   r  )rH   r   r   r  r   r  r   r   r   Z_msg_idZreceiver_public_idrN   rN   rO   r	  1  s&    

zSAMPHubServer._call_all_c                 C   s   |  | || jv rt|}t }i }| ||d|}d | j|< | jrd|  k rdt | krzn n| j|= tdd| j| d urt	| j| }| j|= qt
d qB|S tdd| dd S )	Nsamp::sync::callr   r   r   r   r   r   r   )r   rA   intr   r`   rF   r   r	   r   r   r   )rH   r   r   r   rK   r   responser  rN   rN   rO   rb   F  s(    



 
zSAMPHubServer._call_and_waitc                 C   sB   |  | || jv r,| j| j|||fd ntdd| di S )z
        The main method that gets called for replying. This starts up an
        asynchronous reply thread and returns.
        r   r   r   r   )r   rA   r   _reply_r	   )rH   r   r  r  rN   rN   rO   rc   b  s    


zSAMPHubServer._replyc                 C   s   || j vs|sd S | j | d }|dd\}}}}zbtd||| |dkrl|| j v r|| j|< n(| |}	|||f}
d}| |	|||
 W n< t	y } z$t
d||||t W Y d }~n
d }~0 0 d S )Nr   r  r   zreply {} from {} to {}r
  ZreceiveResponsez0{} reply from client {} to client {} failed [{}])rA   r   r   r   rx   rF   r   r   r   r   r   r   r   )rH   Zresponder_private_keyr  r  Zresponder_public_idZcounterr   r   Zrecipient_msg_tagr   r   r   r   rN   rN   rO   r  p  s,    

zSAMPHubServer._reply_c                 C   s
  |du rt dddlm} t|jD ]}| js<td q&zX| jrj|| j	v rj||d}| j	| 
| n(| j| d }t|jj||g|R   W nJ tjy }	 z0td||d |	j td W Y d}	~	q&d}	~	0 0  dS q&|d t|j d	 }
t |
dS )
a  
        This method is used to retry a SAMP call several times.

        Parameters
        ----------
        recipient_private_key
            The private key of the receiver of the call
        recipient_public_key
            The public key of the receiver of the call
        samp_method_name : str
            The name of the SAMP method to call
        arg_params : tuple
            Any additional arguments to be passed to the SAMP method
        Nr   r   )confr   )zsamp.methodNamer   z*{} XML-RPC endpoint error (attempt {}): {}z failed after z	 attempts)r   r   r  r   Z	n_retriesr   r   r   r)   r-   putrE   getattrr   r   r   ZFaultr   r   rx   ZfaultStringr   )rH   r   r   r   r   r  ZattemptcallbackZhubr   Zerror_messagerN   rN   rO   r     s4    
 zSAMPHubServer._retry_methodc                 C   s.   | j  D ]}| j | d |kr
|  S q
d S r   )rA   r   )rH   r   r   rN   rN   rO   r     s    
z'SAMPHubServer._public_id_to_private_keyc                 C   sH   | j  |  jd7  _W d    n1 s*0    Y  d| j| j||S )Nr   zmsg#{};;{};;{};;{})r5   r<   rx   r@   )rH   r   Zsender_msg_idrN   rN   rO   r    s    ,z!SAMPHubServer._get_new_hub_msg_idc                 C   sJ   | j 0 t | _|d ur(t | j|< W d    n1 s<0    Y  d S r   )r5   r   r:   r;   )rH   r   rN   rN   rO   r     s    
z(SAMPHubServer._update_last_activity_timec                 C   s   dS Nr   rN   )rH   r   	sender_idr   rN   rN   rO   r     s    z#SAMPHubServer._receive_notificationc                 C   s   || j krd|v r6|d dkr6| | j |ti d nVd|v r|d dksV|d dkr| |d d |d d }| | j |td	|id d
S d
S d S )Nr   r   )zsamp.statuszsamp.resultr   zsamp.query.by-metar   r   r   Zidsr   )r   rc   r   r   )rH   r   r  r  r   Zids_listrN   rN   rO   r     s(    





zSAMPHubServer._receive_callc                 C   s   dS r  rN   )rH   r   Zresponder_idr  r  rN   rN   rO   r     s    zSAMPHubServer._receive_responseunknownr   r  c                 C   s   |    |d dvrtdd|s&d}t|trBd|vrBtdd| jd | j|||f | j }| j  |r| 	 }d	
| j|d
 }||d< | j|d
  |S tddd S )Nr   )rr   r   i  z,Request of registration rejected by the Hub.r  r   zLRequest of registration rejected by the Hub (application name not provided).r   z&http://localhost:{}/translator/{}?ref=r   zsamp.url-translatorz-Request of registration rejected by the user.)r   r	   
isinstancedictr0   r  r.   r/   getr   rx   r+   r,   Z
add_client)rH   Zidentity_infoZclient_addressoriginr  Zregister_mapZtranslator_urlrN   rN   rO   rf     s.    






z#SAMPHubServer._web_profile_registerc                 C   sT   |    || jv r>|dkr.|| jv r<| j|= qPt | j|< ntdd| ddS )N0r   r   r   r   )r   rA   r-   rs   rt   r	   )rH   r   ZallowrN   rN   rO   rg     s    


z0SAMPHubServer._web_profile_allowReverseCallbacksc                 C   sn   |    || jv rXg }| j| }z| jr<| }|| q"W n tjyR   Y n0 |S tdd| dd S )Nr   r   r   )	r   rA   r-   r   r   r   rs   r   r	   )rH   r   Ztimeout_secsr  Zcallback_queueZitem_queuedrN   rN   rO   rh   +  s    

z(SAMPHubServer._web_profile_pullCallbacks)NNr   Nr   r   r   r   TNr   r   )NNNN)N)F)N)N)r  r  )D__name__
__module____qualname____doc__rP   propertyrR   re   ri   rq   ry   r   r   r   r   r   r   r   r   r   r>   r   r   r   r   r   r   r   r   r   r   rT   r   rU   r   rV   r   rW   rX   rY   rZ   r[   r\   r]   staticmethodr   r   r^   r   r_   r   r`   r  ra   r	  rb   rc   r  r   r   r  r   r   r   r   rf   rg   rh   rN   rN   rN   rO   r   !   s   @    
X




*
$


(
		)3
' 7
  
)c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	r   aU  
    A base class to make writing Web Profile GUI consent dialogs
    easier.

    The concrete class must:

        1) Poll ``handle_queue`` periodically, using the timer services
           of the GUI's event loop.  This function will call
           ``self.show_dialog`` when a request requires authorization.
           ``self.show_dialog`` will be given the arguments:

              - ``samp_name``: The name of the application making the request.

              - ``details``: A dictionary of details about the client
                making the request.

              - ``client``: A hostname, port pair containing the client
                address.

              - ``origin``: A string containing the origin of the
                request.

        2) Call ``consent`` or ``reject`` based on the user's response to
           the dialog.
    c                 C   sx   z| j  }W n$ tjy"   Y nR ty2   Y nB0 t|d trL|d }n|d d }| ||d |d |d  d S )Nr   r   r   r   )ru   r   rs   r   AttributeErrorr  r   Zshow_dialog)rH   r   Z	samp_namerN   rN   rO   handle_queueV  s    
zWebProfileDialog.handle_queuec                 C   s   | j d d S )NTrv   r  rQ   rN   rN   rO   consente  s    zWebProfileDialog.consentc                 C   s   | j d d S )NFr#  rQ   rN   rN   rO   rejecth  s    zWebProfileDialog.rejectN)r  r  r  r  r"  r$  r%  rN   rN   rN   rO   r   ;  s   )'r   r   r   r2   r4   r   r   r   rs   Zxmlrpc.clientr   r   Zurllib.parser   Zastropyr   Z	constantsr   r   errorsr   r   r	   Zutilsr
   r   r   Zlockfile_helpersr   r   Zstandard_profiler   rM   r   r   __all__Z__doctest_skip__r   r   rN   rN   rN   rO   <module>   s@             $