B
    Ù‹dÄÖ  ã               @   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dˆd	d
„Zedd„ ƒZdd„ Zdd„ Zdd„ Z	dd„ Z
d‰dd„ZdŠdd„Zdd„ Zdd„ Zdd„ Zdd „ Zd‹d"d#„Zed$d%„ ƒZd&d'„ Zd(d)„ Zd*d+„ ZdŒd,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@dŽd‚dƒ„ZAd„d…„ ZBd†d‡„ 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   sD  t t ¡ ƒ| _d| _|| _d | _|| _|| _|| _	|| _
|| _|| _|| _|	| _|
| _|| _d | _i | _d | _d | _d | _d| _tƒ rÌy(t ¡ | _t | jp | j| jp¨d¡ W n tjk
rÊ   d| _Y nX t ¡ | _d | _d | _ d | _!g | _"d | _#i | _$d| _%|| _&|  '¡ | _(d| _)i | _*i | _+i | _,i | _-i | _.i | _/d| _0d S )NFz	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
   ÚsocketÚgetfqdnÚgetaddrinfoÚerrorÚ	threadingÚ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ÚaddrÚportÚlockfileÚtimeoutZclient_timeoutÚmodeÚlabelÚweb_profileZweb_profile_dialogZweb_portZ	pool_size© rS   ú]/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/astropy/samp/hub.pyÚ__init__b   sZ    


zSAMPHubServer.__init__c             C   s   | j S )z$
        The unique hub ID.
        )r   )rJ   rS   rS   rT   Ú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)rJ   ÚserverrS   rS   rT   Ú_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)rW   rX   r[   r\   r]   r^   r_   r`   ra   rb   rc   rd   re   rf   rg   Ú_web_profile_registerÚ"_web_profile_allowReverseCallbacksÚ_web_profile_pullCallbacks)rJ   rh   rS   rS   rT   Ú_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)ÚlogRequestsÚ
allow_noneÚhttpr   ú:r   )r   r!   r0   r"   r   Ú_serverr1   Úgetsocknamer   Ú_urlÚ register_introspection_functionsri   )rJ   ZprotrL   rS   rS   rT   Ú_start_standard_serverì   s    
z$SAMPHubServer._start_standard_serverc             C   sØ   t  d¡| _t  d¡| _t  d¡| _| jd k	rB| j| j_| j| j_yNtd| j	ft
ddd| _| jj ¡ d | _	| j ¡  |  | j¡ t
 d¡ W nB tjk
rÒ   t
 d | j	¡t¡ d| _d | _d | _d | _Y nX d S )Nr   Ú	localhostFT)rn   ro   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.   r/   r)   Úqueue_requestÚqueue_resultr   r*   r   r+   r1   rs   ru   rm   Úinfor4   ÚwarningÚformatr   r(   )rJ   rS   rS   rT   Ú_start_web_profile_serverù   s,    




z'SAMPHubServer._start_web_profile_serverc             C   sj   g }x | j D ]}| ¡ s| |¡ qW x|D ]}| j  |¡ q,W tj||||d}| ¡  | j  |¡ d S )N)ÚgroupÚtargetÚnameÚargs)r;   Úis_aliveÚappendÚremover5   ÚThreadÚstart)rJ   r€   r   r‚   rƒ   r†   ÚtrS   rS   rT   Ú_launch_thread  s    
zSAMPHubServer._launch_threadc             C   s    x| j D ]}|j|d qW d S )N)rO   )r;   Újoin)rJ   rO   r‰   rS   rS   rT   Ú_join_launched_threads(  s    z$SAMPHubServer._join_launched_threadsc          	   C   sŒ   | j dkrd S t ¡ }xp| jr†t d¡ t ¡ }|| dkr| j8 | jd k	rv|| j | j krvt dt¡ |  	¡  d S W d Q R X |}qW d S )Nr   gš™™™™™©?g      ð?z&Timeout expired, Hub is shutting down!)
r%   Útimer   Úsleepr7   r<   ÚwarningsÚwarnr   Ústop)rJ   ÚlastÚnowrS   rS   rT   Ú_timeout_test_hub,  s    


zSAMPHubServer._timeout_test_hubc             C   s¢   | j dkrd S t ¡ }x†| jrœt d¡ t ¡ }|| dkrxX| j ¡ D ]J}|| j|  | j krH|| jkrHt d|› dt	¡ |  
|¡ |  |¡ qHW |}qW d S )Nr   gš™™™™™©?g      ð?zClient z timeout expired!)r&   r   r   rŽ   r=   ÚkeysÚ_hub_private_keyr   r   r   Ú_notify_disconnectionr[   )rJ   r’   r“   Úprivate_keyrS   rS   rT   Ú_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.receiveResponsezsamp.app.ping)Ú_receive_callÚ_receive_notificationÚ_receive_responserX   )rJ   Úmethodrƒ   rS   rS   rT   Ú_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)z	samp.namezsamp.description.textzauthor.namezsamp.documentation.urlzsamp.icon.urlzsamp.self-idzsamp.private-key)zsamp.app.pingzx-samp.query.by-meta)	r$   rt   rZ   rA   rB   r–   rY   r\   r^   )rJ   Zhub_metadataÚresultrS   rS   rT   Ú_setup_hub_as_client]  s    

z"SAMPHubServer._setup_hub_as_clientFc             C   s   | j rtdƒ‚| jdk	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lockfilenamerP   Zhub_idZ
hub_paramszHub started)r   r   r    r(   r   rv   r   r   r#   rV   ÚparamsÚ_update_last_activity_timer    Ú_start_threadsr   r|   r8   r‹   )rJ   ÚwaitrS   rS   rT   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)
        zsamp.secretzsamp.hub.xmlrpc.urlzsamp.profile.versionzhub.idzHub z	hub.label)rA   rt   r   rV   r$   )rJ   r¡   rS   rS   rT   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 k	r”| j ¡  | j
d k	r¨| j
 ¡  d S )N)r   Tr   zHub timeout test)r   r‚   zClient timeout test)r5   r‡   Ú_serve_foreverr8   Údaemonr%   r”   r9   r&   r™   r:   r   rˆ   )rJ   rS   rS   rT   r£   ­  s(    









zSAMPHubServer._start_threadsc             C   s    | j d k	r| j S tt ¡ ƒS d S )N)r?   r   r   r   )rJ   rS   rS   rT   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...Fzsamp.secretg      $@)rO   r   r   zHub stopped.)r   r   r|   Ú_notify_shutdownr    ÚosÚpathÚisfiler   rA   r†   Ú_join_all_threadsr>   r@   rB   rD   rC   rE   rF   rG   r<   )rJ   ZlockfiledictrS   rS   rT   r‘   Ï  s*    


zSAMPHubServer.stopc             C   s¤   t  ¡ }| j|k	r0| jj|d | j ¡ s0d | _| jd k	rb| j|k	rb| jj|d | j ¡ sbd | _| jd k	r”| j|k	r”| jj|d | j ¡ s”d | _| j|d d S )N)rO   )r5   Úcurrent_threadr8   r‹   r„   r9   r:   rŒ   )rJ   rO   r¬   rS   rS   rT   r«   ó  s    



zSAMPHubServer._join_all_threadsc             C   s   | j S )z™Return an information concerning the Hub running status.

        Returns
        -------
        running : bool
            Is the hub running?
        )r   )rJ   rS   rS   rT   Ú
is_running  s    	zSAMPHubServer.is_runningc          
   C   s<  x| j ryt | jjgg g d¡d }W n4 tk
r^ } zt d|› t¡ W d d }~X Y nX |rn| j ¡  | j	r| j
d kr°y| j ¡ }W n tjk
r¢   Y nX t|| jƒ yt | jjgg g d¡d }W n6 tk
r } zt d|› t¡ W d d }~X Y qX |r| j ¡  qW | j ¡  | jd k	r8| j ¡  d S )Ng{®Gáz„?r   z*Call to select() in SAMPHubServer failed: )r   Úselectrr   r1   ÚOSErrorr   r   r   Úhandle_requestr(   r)   r-   Ú
get_nowaitrx   ÚEmptyr   r.   r+   Úserver_close)rJ   Z
read_readyÚexcÚrequestrS   rS   rT   r¥     s2    


zSAMPHubServer._serve_foreverc          	   C   sZ   t  d¡}xJ|D ]B}|| jkrx2| j| D ]$}|  | j| j| d di dœ¡ q*W qW d S )Nzsamp.hub.event.shutdownr   )z
samp.mtypezsamp.params)r   Úget_mtype_subtypesrE   Ú_notify_r–   rC   )rJ   ÚmsubsÚmtypeÚkeyrS   rS   rT   r§   :  s    


zSAMPHubServer._notify_shutdownc          	   C   sl   t  d¡}x\|D ]T}|| jkr| j| d }x6| j| D ](}|  | j| j| d dd|idœ¡ q8W qW d S )Nzsamp.hub.event.registerr   rV   )z
samp.mtypezsamp.params)r   r¶   rE   rC   rb   r–   )rJ   r˜   r¸   r¹   Ú	public_idrº   rS   rS   rT   Ú_notify_registerD  s    


zSAMPHubServer._notify_registerc          	   C   st   t  d¡}xd|D ]\}|| jkr| j| d }x>| j| D ]0}||kr8|  | j| j| d dd|idœ¡ q8W qW d S )Nzsamp.hub.event.unregisterr   rV   )z
samp.mtypezsamp.params)r   r¶   rE   rC   rb   r–   )rJ   r˜   r¸   r¹   r»   rº   rS   rS   rT   Ú_notify_unregisterP  s    


z SAMPHubServer._notify_unregisterc          
   C   st   t  d¡}xd|D ]\}|| jkr| j| d }x>| j| D ]0}|  | j| j| d d|| j| dœdœ¡ q8W qW d S )Nzsamp.hub.event.metadatar   )rV   Úmetadata)z
samp.mtypezsamp.params)r   r¶   rE   rC   rb   r–   rD   )rJ   r˜   r¸   r¹   r»   rº   rS   rS   rT   Ú_notify_metadata\  s    


zSAMPHubServer._notify_metadatac          
   C   st   t  d¡}xd|D ]\}|| jkr| j| d }x>| j| D ]0}|  | j| j| d d|| j| dœdœ¡ q8W qW d S )Nzsamp.hub.event.subscriptionsr   )rV   Zsubscriptions)z
samp.mtypezsamp.params)r   r¶   rE   rC   rb   r–   rF   )rJ   r˜   r¸   r¹   r»   rº   rS   rS   rT   Ú_notify_subscriptionsj  s    


z#SAMPHubServer._notify_subscriptionsc          	   C   sŠ   dd„ }t  d¡}| j| d }| j| d }xV|D ]N}|| jkr4|| j| kr4t d|› ¡ | j|||| jdddid	œfd
 q4W d S )Nc             S   s   | j j |||¡ d S )N)ÚsampÚclientÚreceiveNotification)Úendpointr˜   Úhub_public_idÚmessagerS   rS   rT   Ú_xmlrpc_call_disconnecty  s    zDSAMPHubServer._notify_disconnection.<locals>._xmlrpc_call_disconnectzsamp.hub.disconnectr   r   znotify disconnection to ÚreasonzTimeout expired!)z
samp.mtypezsamp.params)r   rƒ   )	r   r¶   rC   rG   rE   r   ÚdebugrŠ   rB   )rJ   r˜   rÇ   r¸   r»   rÄ   r¹   rS   rS   rT   r—   w  s    

z#SAMPHubServer._notify_disconnectionc             C   s   |   ¡  t d¡ dS )NZpingÚ1)r¢   r   rÉ   )rJ   rS   rS   rT   rX   ‰  s    
zSAMPHubServer._pingc             C   sL   g }xB| j D ]8}|| j | kr| j | | |kr| | j| d ¡ qW |S )Nr   )rD   r…   rC   )rJ   rº   ÚvalueZpublic_id_listZ
private_idrS   rS   rT   Ú_query_by_metadataŽ  s    z SAMPHubServer._query_by_metadatac             C   s¦   |   |¡ || jk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   )ro   é   zPrivate-key z expired or invalid.)r¢   rC   r–   r   rž   rG   r   rÉ   r   r'   ÚxmlrpcÚServerProxyr	   )rJ   r˜   Zxmlrpc_addrr»   Zserver_proxy_poolrS   rS   rT   rY   —  s     



z"SAMPHubServer._set_xmlrpc_callbackc          	   C   sh   | j  |  ¡ \}}W d Q R X |t ¡ f| j|< |  |¡ |  |¡ t d|› d|› ¡ ||| jdœS )Nzregister: private-key = z and self-id = )zsamp.self-idzsamp.private-keyzsamp.hub-id)	r7   Ú_get_new_idsr   rC   r¢   r¼   r   rÉ   rB   )rJ   r˜   r»   rS   rS   rT   Ú_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¢   rA   rÒ   r	   )rJ   rK   rS   rS   rT   rZ   ¾  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   rI   )rJ   r˜   r»   rS   rS   rT   rÑ   Æ  s    
zSAMPHubServer._get_new_idsc          	   C   s  |   ¡  d}|  |¡ | jÊ || jkr@| j| d }| j|= ndS || jkrV| j|= || jkrh| j|= x0| j ¡ D ]"}|| j| krt| j|  |¡ qtW || j	kr¬| j	|= || j
kr¾| j
|= | jrâ|| jkrÖ| j|= | j |¡ W d Q R X t d|› d|› d¡ dS )Nr   r   zunregister z (ú))r¢   r½   r7   rC   rD   rF   rE   r•   r†   rG   r=   r(   r,   r+   Zremove_clientr   rÉ   )rJ   r˜   Z
public_keyr¹   rS   rS   rT   r[   Ï  s2    







zSAMPHubServer._unregisterc             C   sV   |   |¡ || jkr@t d |t|ƒ¡¡ || j|< |  |¡ ntdd|› dƒ‚dS )Nz0declare_metadata: private-key = {} metadata = {}rÎ   zPrivate-key z expired or invalid.r   )	r¢   rC   r   rÉ   r~   r   rD   r¿   r	   )rJ   r˜   r¾   rS   rS   rT   r\   ø  s    


zSAMPHubServer._declare_metadatac             C   sŠ   |   |¡ || jkrt|  |¡}t d ||¡¡ |d k	rh|| jkrbt d| j| › ¡ | j| S i S q†tddƒ‚ntdd|› dƒ‚d S )Nz-get_metadata: private-key = {} client-id = {}z--> metadata = é   zInvalid client IDrÎ   zPrivate-key z expired or invalid.)r¢   rC   Ú_public_id_to_private_keyr   rÉ   r~   rD   r	   )rJ   r˜   Ú	client_idÚclient_private_keyrS   rS   rT   r]     s    





zSAMPHubServer._get_metadatac          	   C   s`  |   |¡ || jkrJt d |t|ƒ¡¡ || jkrx| j| }x6|D ].}y| j|  |¡ W qF t	k
rr   Y qFX qFW t
 |¡| j|< t
 |¡}xL|D ]D}| d¡r˜x4|D ],}| |d d… ¡r¬||kr¬||kr¬||= q¬W q˜W t d |t|ƒ¡¡ xF|D ]>}|| jkr.|| j| kr:| j|  |¡ qü|g| j|< qüW |  |¡ ntdd|› dƒ‚dS )	Nz3declare_subscriptions: private-key = {} mtypes = {}Ú*r   z;declare_subscriptions: subscriptions accepted from {} => {}rÎ   zPrivate-key z expired or invalid.r   )r¢   rC   r   rÉ   r~   r   rF   rE   r†   Ú
ValueErrorÚcopyÚdeepcopyÚendswithÚ
startswithr…   rÀ   r	   )rJ   r˜   ZmtypesZprev_mtypesr¹   Zoriginal_mtypesZmtype2rS   rS   rT   r^     s<    









z$SAMPHubServer._declare_subscriptionsc             C   sŽ   |   |¡ || jkrx|  |¡}|d k	rl|| jkrVt d |t| j| ƒ¡¡ | j| S t d |¡¡ i S qŠtddƒ‚ntdd|› dƒ‚d S )Nz-get_subscriptions: client-id = {} mtypes = {}z2get_subscriptions: client-id = {} mtypes = missingrÕ   zInvalid client IDrÎ   zPrivate-key z expired or invalid.)	r¢   rC   rÖ   rF   r   rÉ   r~   r   r	   )rJ   r˜   r×   rØ   rS   rS   rT   r_   G  s    




z SAMPHubServer._get_subscriptionsc             C   st   |   |¡ || jkr^g }x.| j ¡ D ] }||kr$| | j| d ¡ q$W t d ||¡¡ |S tdd|› dƒ‚d S )Nr   z5get_registered_clients: private_key = {} clients = {}rÎ   zPrivate-key z expired or invalid.)r¢   rC   r•   r…   r   rÉ   r~   r	   )rJ   r˜   Zreg_clientsÚpkeyrS   rS   rT   r`   \  s    


z%SAMPHubServer._get_registered_clientsc             C   s€   |   |¡ || jkrji }x8| j ¡ D ]*}||kr$|  ||¡r$i || j| d < q$W t d |||¡¡ |S tdd|› dƒ‚d S )Nr   z@get_subscribed_clients: private_key = {} mtype = {} clients = {}rÎ   zPrivate-key z expired or invalid.)r¢   rC   r•   Ú_is_subscribedr   rÉ   r~   r	   )rJ   r˜   r¹   Zsub_clientsrß   rS   rS   rT   ra   k  s    

z%SAMPHubServer._get_subscribed_clientsc             C   s€   g }|   d¡}ttt|ƒƒƒ}| ¡  | d¡ xJ|D ]B}d |d|d … ¡}|| krn|dkrj|d }nd}| |¡ q6W |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¹   Úsubtypesr¸   ZindexesÚiZ	tmp_mtyperS   rS   rT   r¶   |  s    



z SAMPHubServer.get_mtype_subtypesc             C   s<   d}t  |¡}x(|D ] }|| jkr|| j| krd}qW |S )NFT)r   r¶   rE   )rJ   r˜   r¹   Z
subscribedr¸   ZmsubrS   rS   rT   rà   ¤  s    


zSAMPHubServer._is_subscribedc             C   st   |   |¡ || jkr^|  |  |¡|d ¡dkrDtdd ||d ¡ƒ‚| j| j|||fd i S tdd|› dƒ‚d S )	Nz
samp.mtypeFé   z$Client {} not subscribed to MType {})r   rƒ   rÎ   zPrivate-key z expired or invalid.)r¢   rC   rà   rÖ   r	   r~   rŠ   r·   )rJ   r˜   Úrecipient_idrÆ   rS   rS   rT   rb   ±  s    



zSAMPHubServer._notifyc       	      C   s¢   || j krd S | j | d }yBt d |d ||¡¡ |  |¡}||f}d}|  ||||¡ W n> tk
rœ } z t d |d |||¡t	¡ W d d }~X Y nX d S )Nr   znotify {} from {} to {}z
samp.mtyperÃ   z7{} notification from client {} to client {} failed [{}])
rC   r   rÉ   r~   rÖ   Ú_retry_methodÚ	Exceptionr   r   r   )	rJ   Úsender_private_keyÚrecipient_public_idrÆ   Úsender_public_idÚrecipient_private_keyÚ
arg_paramsÚsamp_method_namer´   rS   rS   rT   r·   Á  s"    

zSAMPHubServer._notify_c             C   sL   |   |¡ || jkr6d|kr&tddƒ‚|  ||¡}|S tdd|› dƒ‚d S )Nz
samp.mtypeé   zsamp.mtype keyword is missingrÎ   zPrivate-key z expired or invalid.)r¢   rC   r	   Ú_notify_all_)rJ   r˜   rÆ   Úrecipient_idsrS   rS   rT   rc   Û  s    


zSAMPHubServer._notify_allc             C   sx   g }t  |d ¡}x`|D ]X}|| jkrxH| j| D ]:}||kr2| j| d }| |¡ | j| j|||fd q2W qW |S )Nz
samp.mtyper   )r   rƒ   )r   r¶   rE   rC   r…   rŠ   rb   )rJ   rì   rÆ   rô   r¸   r¹   rº   Z_recipient_idrS   rS   rT   ró   æ  s    


zSAMPHubServer._notify_all_c             C   s’   |   |¡ || jkr||  |  |¡|d ¡dkrDtdd ||d ¡ƒ‚| j| d }|  ||¡}| j| j|||||fd |S tdd|› d	ƒ‚d S )
Nz
samp.mtypeFrè   z$Client {} not subscribed to MType {}r   )r   rƒ   rÎ   zPrivate-key z expired or invalid.)	r¢   rC   rà   rÖ   r	   r~   Ú_get_new_hub_msg_idrŠ   Ú_call_)rJ   r˜   ré   Úmsg_tagrÆ   r»   Úmsg_idrS   rS   rT   rd   ø  s    


zSAMPHubServer._callc       
      C   s´   || j krd S yPt d | d¡d |||d ¡¡ |  |¡}|||f}d}|  ||||¡ W nP tk
r® }	 z2t 	d |d | d¡d ||t
|	ƒ|	¡t¡ W d d }	~	X Y nX d S )Nzcall {} from {} to {} ({})z;;r   z
samp.mtypeZreceiveCallz5{} call {} from client {} to client {} failed [{},{}])rC   r   rÉ   r~   rá   rÖ   rê   rë   r   r   Útyper   )
rJ   rì   rî   rí   rø   rÆ   rï   rð   Zsamp_methodNamer´   rS   rS   rT   rö   	  s"    


zSAMPHubServer._call_c             C   sd   |   |¡ || jkrNd|kr,tdd |¡ƒ‚| j| d }|  ||||¡}|S tdd|› dƒ‚d S )Nz
samp.mtyperò   z5samp.mtype keyword is missing in message tagged as {}r   rÎ   zPrivate-key z expired or invalid.)r¢   rC   r	   r~   Ú
_call_all_)rJ   r˜   r÷   rÆ   r»   rø   rS   rS   rT   re   #  s    

zSAMPHubServer._call_allc          	   C   s†   i }t  |d ¡}xn|D ]f}|| jkrxV| j| D ]H}||kr2|  ||¡}	| j| d }
|	||
< | j| j|||
|	|fd q2W qW |S )Nz
samp.mtyper   )r   rƒ   )r   r¶   rE   rõ   rC   rŠ   rö   )rJ   rì   rî   r÷   rÆ   rø   r¸   r¹   rº   Z_msg_idZreceiver_public_idrS   rS   rT   rú   1  s     

zSAMPHubServer._call_all_c             C   sÌ   |   |¡ || jkr¶t|ƒ}t ¡ }i }|  ||d|¡}d | j|< xn| jr°d|  k rft ¡ | kr|n n| j|= tddƒ‚| j| d k	r¤t 	| j| ¡}| j|= P t 
d¡ qDW |S tdd|› dƒ‚d S )	Nzsamp::sync::callr   r   zTimeout expired!g{®Gáz„?rÎ   zPrivate-key z expired or invalid.)r¢   rC   Úintr   rd   rH   r   r	   rÛ   rÜ   rŽ   )rJ   r˜   ré   rÆ   rO   r“   Úresponserø   rS   rS   rT   rf   F  s&    



 
zSAMPHubServer._call_and_waitc             C   sB   |   |¡ || jk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Î   zPrivate-key z expired or invalid.)r¢   rC   rŠ   Ú_reply_r	   )rJ   r˜   rø   rü   rS   rS   rT   rg   b  s    

zSAMPHubServer._replyc             C   sÖ   || j ks|sd S | j | d }| dd¡\}}}}ybt d |||¡¡ |dkrl|| j ¡ kr”|| j|< n(|  |¡}	|||f}
d}|  |	|||
¡ W n: t	k
rÐ } zt
 d ||||¡t¡ W d d }~X Y nX d S )Nr   z;;rò   zreply {} from {} to {}zsamp::sync::callZreceiveResponsez0{} reply from client {} to client {} failed [{}])rC   rá   r   rÉ   r~   rH   r•   rÖ   rê   rë   r   r   r   )rJ   Zresponder_private_keyrø   rü   Zresponder_public_idÚcounterrÅ   rí   Zrecipient_msg_tagrï   rð   rñ   r´   rS   rS   rT   rý   p  s&    

zSAMPHubServer._reply_c             C   s  |dkrt dƒ‚ddlm} xÈt|jƒD ]º}| js>t d¡ q(yV| jrl|| j	krl||dœ}| j	|  
|¡ n&| j| d }t|jj|ƒ|f|žŽ  W nH tjk
rÜ }	 z(t d ||d |	j¡¡ t d¡ W dd}	~	X Y q(X dS q(W |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
        NzInvalid client IDr   )Úconfg{®Gáz„?)zsamp.methodNamezsamp.paramsz*{} XML-RPC endpoint error (attempt {}): {}z failed after z	 attempts)r   r   rÿ   rã   Z	n_retriesr   r   rŽ   r(   r,   ÚputrG   ÚgetattrrÁ   rÂ   rÏ   ÚFaultr   rÉ   r~   ÚfaultStringr   )rJ   rï   rí   rñ   rð   rÿ   ÚattemptÚcallbackZhubr´   Úerror_messagerS   rS   rT   rê     s.    


zSAMPHubServer._retry_methodc             C   s.   x(| j  ¡ D ]}| j | d |kr|S qW d S )Nr   )rC   r•   )rJ   r»   r˜   rS   rS   rT   rÖ   Ç  s    z'SAMPHubServer._public_id_to_private_keyc          	   C   s4   | j  |  jd7  _W d Q R X d | j| j||¡S )Nr   zmsg#{};;{};;{};;{})r7   r>   r~   rB   )rJ   rî   Zsender_msg_idrS   rS   rT   rõ   Î  s
    z!SAMPHubServer._get_new_hub_msg_idc          	   C   s6   | j & t ¡ | _|d k	r(t ¡ | j|< W d Q R X d S )N)r7   r   r<   r=   )rJ   r˜   rS   rS   rT   r¢   Õ  s    
z(SAMPHubServer._update_last_activity_timec             C   s   dS )Nr   rS   )rJ   r˜   Ú	sender_idrÆ   rS   rS   rT   r›   Û  s    z#SAMPHubServer._receive_notificationc             C   s˜   || j krd|kr6|d dkr6|  | j |ti dœ¡ nVd|krŒ|d dksV|d dkrŒ|  |d d |d d ¡}|  | j |td	|idœ¡ d
S d
S d S )Nz
samp.mtypezsamp.app.ping)zsamp.statuszsamp.resultzx-samp.query.by-metazsamp.query.by-metazsamp.paramsrº   rË   Zidsr   )r–   rg   r   rÌ   )rJ   r˜   r  rø   rÆ   Zids_listrS   rS   rT   rš   Þ  s    


zSAMPHubServer._receive_callc             C   s   dS )Nr   rS   )rJ   r˜   Zresponder_idr÷   rü   rS   rS   rT   rœ   ó  s    zSAMPHubServer._receive_response©Úunknownr   r	  c             C   s¼   |   ¡  |d dkrtddƒ‚|s&d}t|tƒrBd|krBtddƒ‚| j d¡ | j |||f¡ | j ¡ }| j ¡  |r®|  	¡ }d	 
| j|d
 ¡}||d< | j |d
 ¡ |S tddƒ‚d S )Nr   )rw   z	127.0.0.1i“  z,Request of registration rejected by the Hub.r	  z	samp.namezLRequest of registration rejected by the Hub (application name not provided).r¤   z&http://localhost:{}/translator/{}?ref=zsamp.private-keyzsamp.url-translatorz-Request of registration rejected by the user.)r¢   r	   Ú
isinstanceÚdictr/   r   r-   r.   ÚgetrÒ   r~   r*   r+   Z
add_client)rJ   Zidentity_infoÚclient_addressÚoriginrü   Zregister_mapZtranslator_urlrS   rS   rT   rj   ö  s*    





z#SAMPHubServer._web_profile_registerc             C   sT   |   ¡  || jkr>|dkr.|| jkr<| j|= qPt ¡ | j|< ntdd|› dƒ‚dS )NÚ0rÎ   zPrivate-key z expired or invalid.r   )r¢   rC   r,   rx   ry   r	   )rJ   r˜   ZallowrS   rS   rT   rk     s    


z0SAMPHubServer._web_profile_allowReverseCallbacksc             C   st   |   ¡  || jkr^g }| j| }y"x| jr>| ¡ }| |¡ q$W W n tjk
rX   Y nX |S tdd|› dƒ‚d S )NrÎ   zPrivate-key z expired or invalid.)	r¢   rC   r,   r   r±   r…   rx   r²   r	   )rJ   r˜   Ztimeout_secsr  Zcallback_queueZitem_queuedrS   rS   rT   rl   +  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__rU   ÚpropertyrV   ri   rm   rv   r   rŠ   rŒ   r”   r™   rž   r    rˆ   r¡   r£   r@   r‘   r«   r­   r¥   r§   r¼   r½   r¿   rÀ   r—   rX   rÌ   rY   rÒ   rZ   rÑ   r[   r\   r]   r^   r_   r`   ra   Ústaticmethodr¶   rà   rb   r·   rc   ró   rd   rö   re   rú   rf   rg   rý   rê   rÖ   rõ   r¢   r›   rš   rœ   rj   rk   rl   rS   rS   rS   rT   r   !   s†   ?   
U



*$
(
		)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   s|   y| j  ¡ }W n( tjk
r$   Y nT tk
r6   Y nBX t|d tƒrP|d }n|d d }|  ||d |d |d ¡ d S )Nr   z	samp.namer   rè   )rz   r±   rx   r²   ÚAttributeErrorr
  r   Zshow_dialog)rJ   rµ   Z	samp_namerS   rS   rT   Úhandle_queueV  s    
zWebProfileDialog.handle_queuec             C   s   | j  d¡ d S )NT)r{   r   )rJ   rS   rS   rT   Úconsente  s    zWebProfileDialog.consentc             C   s   | j  d¡ d S )NF)r{   r   )rJ   rS   rS   rT   Úrejecth  s    zWebProfileDialog.rejectN)r  r  r  r  r  r  r  rS   rS   rS   rT   r   ;  s   )'rÛ   r¨   r®   r1   r5   r   r   r   rx   Úxmlrpc.clientrÂ   rÏ   Úurllib.parser   Zastropyr   Ú	constantsr   r   Úerrorsr   r   r	   Úutilsr
   r   r   Zlockfile_helpersr   r   Zstandard_profiler   rR   r   r   Ú__all__Z__doctest_skip__r   r   rS   rS   rS   rT   Ú<module>   s@             $