๓
฿ศ[c           @` s  d  d l  m Z m Z m Z m Z d  d l Z d  d l Z d  d l Z d  d l Z d  d l	 Z	 d  d l
 Z
 d d l m Z d d l m Z d d l m Z m Z d d l m Z d d	 l m Z m Z d d
 l m Z m Z d d l m Z d g Z d e f d     YZ d S(   i    (   t   absolute_importt   divisiont   print_functiont   unicode_literalsNi   (   t   log(   t
   urlunparsei   (   t   SAMP_STATUS_OKt   SAMP_STATUS_WARNING(   t   SAMPHubServer(   t   SAMPClientErrort   SAMPWarning(   t   internet_ont   get_num_args(   t   ThreadingXMLRPCServeru
   SAMPClientt
   SAMPClientc           B` s^  e  Z d  Z d! d! d! d! d e d  Z d   Z d d  Z e d    Z	 e d    Z
 d   Z d	   Z d
   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z e d! d  Z e d! d  Z e d! d  Z d   Z e d  Z e d  Z d   Z d! d  Z d   Z d   Z d   Z d! d  Z  d! d  Z! d   Z" d    Z# RS("   uฎ  
    Utility class which provides facilities to create and manage a SAMP
    compliant XML-RPC server that acts as SAMP callable client application.

    Parameters
    ----------
    hub : :class:`~astropy.samp.SAMPHubProxy`
        An instance of :class:`~astropy.samp.SAMPHubProxy` to be
        used for messaging with the SAMP Hub.

    name : str, optional
        Client name (corresponding to ``samp.name`` metadata keyword).

    description : str, optional
        Client description (corresponding to ``samp.description.text`` metadata
        keyword).

    metadata : dict, optional
        Client application metadata in the standard SAMP format.

    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.

    callable : bool, optional
        Whether the client can receive calls and notifications. If set to
        `False`, then the client can send notifications and calls, but can not
        receive any.
    i    c   	      C` s{  t  |  _ t  |  _ | d  k r' i  } n  | d  k	 r@ | | d <n  | d  k	 rY | | d <n  | |  _ | |  _ | |  _ d  |  _ | |  _ d  |  _	 d  |  _
 d  |  _ d  |  _ i  |  _ i |  j i  g d 6|  j i  g d 6|  _ i  |  _ d |  _ t   rRy8 t j   |  _ t j |  j p|  j |  j p*d  WqRt j k
 rNd |  _ qRXn  | |  _ |  j rwt j d |  j  |  _ t |  j _ t |  j p|  j |  j f d t  d	 t |  _	 |  j	 j    |  j	 j! |  j" d
  |  j	 j! |  j# d  |  j	 j! |  j$ d  |  j d k r2|  j	 j j%   d |  _ n  d } t& | d j' |  j pS|  j |  j  d d d d f  |  _ n  d  S(   Nu	   samp.nameu   samp.description.textu   samp.app.pingu   client.env.getu	   127.0.0.1i    t   targett   logRequestst
   allow_noneu   samp.client.receiveNotificationu   samp.client.receiveCallu   samp.client.receiveResponsei   u   httpu   {0}:{1}u    ((   t   Falset   _is_runningt   _is_registeredt   Nonet	   _metadatat   _addrt   _portt   _xmlrpcAddrt	   _callablet   clientt
   _public_idt   _private_keyt   _hub_idt   _notification_bindingst   _pingt   _client_env_gett   _call_bindingst   _response_bindingst
   _host_nameR   t   sockett   getfqdnt   getaddrinfot   errort   hubt	   threadingt   Threadt   _serve_forevert   _threadt   Truet   daemonR   t    register_introspection_functionst   register_functiont   receive_notificationt   receive_callt   receive_responset   getsocknameR   t   format(	   t   selfR)   t   namet   descriptiont   metadatat   addrt   portt   callablet   protocol(    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt   __init__@   sZ    																)			c         C` s#   |  j  r t |  _ |  j   n  d S(   uฐ   
        Start the client in a separate thread (non-blocking).

        This only has an effect if ``callable`` was set to `True` when
        initializing the client.
        N(   R   R.   R   t   _run_client(   R7   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt   start   s    		g      $@c         C` s_   t  |  _ |  j r4 |  j j   r4 |  j j |  n  |  j j   r[ t d j |    n  d S(   uร   
        Stop the client.

        Parameters
        ----------
        timeout : float
            Timeout after which to give up if the client cannot be cleanly
            shut down.
        u4   Client was not shut down successfully (timeout={0}s)N(   R   R   R   R-   t   is_alivet   joinR	   R6   (   R7   t   timeout(    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt   stop   s    		c         C` s   |  j  S(   u:   
        Whether the client is currently running.
        (   R   (   R7   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt
   is_runningฃ   s    c         C` s   |  j  S(   u=   
        Whether the client is currently registered.
        (   R   (   R7   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt   is_registeredช   s    c         C` s   |  j  r |  j j   n  d  S(   N(   R   R-   RA   (   R7   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyR@   ฑ   s    	c         C` s   x~ |  j  r y) t j |  j j g g  g  d  d } Wn/ t j k
 rf } t j d j |  t  q X| r |  j j	   q q W|  j j
   d  S(   Ngน?i    u(   Call to select in SAMPClient failed: {0}(   R   t   selectR   R%   R(   t   warningst   warnR6   R
   t   handle_requestt   server_close(   R7   t
   read_readyt   exc(    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyR,   ต   s    )c         C` s.   i t  d 6i  d 6} |  j j | | |  d  S(   Nu   samp.statusu   samp.result(   R   R)   t   reply(   R7   t   private_keyt	   sender_idt   msg_idt	   msg_mtypet
   msg_paramst   messageRO   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyR    ย   s    c         C` s   | d t  j k r< i t d 6i t  j | d d 6d 6} n) i t d 6i d d 6d 6i d d 6d 6} |  j j | | |  d  S(	   Nu   nameu   samp.statusu   valueu   samp.resultu    u!   Environment variable not defined.u   samp.errortxtu
   samp.error(   t   ost   environR   R   R)   RO   (   R7   RP   RQ   RR   RS   RT   RU   RO   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyR!   ษ   s    

c   	      C` sฮ   | |  j    k rส d | k rส | d } | d =| d } | d =t j |  } xx | D]m } | |  j k rV |  j | d } t |  d k rง | | | | | |  qร | | | d  | | |  qV qV Wn  d S(   Nu
   samp.mtypeu   samp.paramsi    i   u    (   t   get_private_keyR   t   get_mtype_subtypesR   R   R   (	   R7   RP   RQ   RU   RS   RT   t   msubst   mtypet
   bound_func(    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt   _handle_notificationื   s    

c         C` s   |  j  | | |  S(   u^  
        Standard callable client ``receive_notification`` method.

        This method is automatically handled when the
        :meth:`~astropy.samp.client.SAMPClient.bind_receive_notification`
        method is used to bind distinct operations to MTypes. In case of a
        customized callable client implementation that inherits from the
        :class:`~astropy.samp.SAMPClient` class this method should be
        overwritten.

        .. note:: When overwritten, this method must always return
                  a string result (even empty).

        Parameters
        ----------
        private_key : str
            Client private key.

        sender_id : str
            Sender public ID.

        message : dict
            Received message.

        Returns
        -------
        confirmation : str
            Any confirmation string.
        (   R]   (   R7   RP   RQ   RU   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyR2   ํ   s    c   	      C` s   | |  j    k r d | k r | d } | d =| d } | d =t j |  } xG | D]< } | |  j k rV |  j | d | | | | | |  qV qV Wn  d S(   Nu
   samp.mtypeu   samp.paramsi    u    (   RX   R   RY   R"   (	   R7   RP   RQ   RR   RU   RS   RT   RZ   R[   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt   _handle_call  s    

c         C` s   |  j  | | | |  S(   u  
        Standard callable client ``receive_call`` method.

        This method is automatically handled when the
        :meth:`~astropy.samp.client.SAMPClient.bind_receive_call` method is
        used to bind distinct operations to MTypes. In case of a customized
        callable client implementation that inherits from the
        :class:`~astropy.samp.SAMPClient` class this method should be
        overwritten.

        .. note:: When overwritten, this method must always return
                  a string result (even empty).

        Parameters
        ----------
        private_key : str
            Client private key.

        sender_id : str
            Sender public ID.

        msg_id : str
            Message ID received.

        message : dict
            Received message.

        Returns
        -------
        confirmation : str
            Any confirmation string.
        (   R^   (   R7   RP   RQ   RR   RU   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyR3      s    !c         C` sB   | |  j    k r> | |  j k r> |  j | | | | |  n  d S(   Nu    (   RX   R#   (   R7   RP   t   responder_idt   msg_tagt   response(    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt   _handle_responseC  s
    c         C` s   |  j  | | | |  S(   u  
        Standard callable client ``receive_response`` method.

        This method is automatically handled when the
        :meth:`~astropy.samp.client.SAMPClient.bind_receive_response` method
        is used to bind distinct operations to MTypes. In case of a customized
        callable client implementation that inherits from the
        :class:`~astropy.samp.SAMPClient` class this method should be
        overwritten.

        .. note:: When overwritten, this method must always return
                  a string result (even empty).

        Parameters
        ----------
        private_key : str
            Client private key.

        responder_id : str
            Responder public ID.

        msg_tag : str
            Response message tag.

        response : dict
            Received response.

        Returns
        -------
        confirmation : str
            Any confirmation string.
        (   Rb   (   R7   RP   R_   R`   Ra   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyR4   J  s    !c         C` s<   |  j  | | d | d | |  j | | d | d | d S(   u  
        Bind a specific MType to a function or class method, being intended for
        a call or a notification.

        The function must be of the form::

            def my_function_or_method(<self,> private_key, sender_id, msg_id,
                                      mtype, params, extra)

        where ``private_key`` is the client private-key, ``sender_id`` is the
        notification sender ID, ``msg_id`` is the Hub message-id (calls only,
        otherwise is `None`), ``mtype`` is the message MType, ``params`` is the
        message parameter set (content of ``"samp.params"``) and ``extra`` is a
        dictionary containing any extra message map entry. The client is
        automatically declared subscribed to the MType by default.

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

        function : callable
            Application function to be used when ``mtype`` is received.

        declare : bool, optional
            Specify whether the client must be automatically declared as
            subscribed to the MType (see also
            :meth:`~astropy.samp.client.SAMPClient.declare_subscriptions`).

        metadata : dict, optional
            Dictionary containing additional metadata to declare associated
            with the MType subscribed to (see also
            :meth:`~astropy.samp.client.SAMPClient.declare_subscriptions`).
        t   declareR:   N(   t   bind_receive_callt   bind_receive_notification(   R7   R[   t   functionRc   R:   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt   bind_receive_messagen  s    %c         C` sQ   |  j  rA | s i  } n  | | g |  j | <| rM |  j   qM n t d   d S(   u  
        Bind a specific MType notification to a function or class method.

        The function must be of the form::

            def my_function_or_method(<self,> private_key, sender_id, mtype,
                                      params, extra)

        where ``private_key`` is the client private-key, ``sender_id`` is the
        notification sender ID, ``mtype`` is the message MType, ``params`` is
        the notified message parameter set (content of ``"samp.params"``) and
        ``extra`` is a dictionary containing any extra message map entry. The
        client is automatically declared subscribed to the MType by default.

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

        function : callable
            Application function to be used when ``mtype`` is received.

        declare : bool, optional
            Specify whether the client must be automatically declared as
            subscribed to the MType (see also
            :meth:`~astropy.samp.client.SAMPClient.declare_subscriptions`).

        metadata : dict, optional
            Dictionary containing additional metadata to declare associated
            with the MType subscribed to (see also
            :meth:`~astropy.samp.client.SAMPClient.declare_subscriptions`).
        u   Client not callable.N(   R   R   t   _declare_subscriptionsR	   (   R7   R[   Rf   Rc   R:   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyRe     s    !		c         C` sQ   |  j  rA | s i  } n  | | g |  j | <| rM |  j   qM n t d   d S(   u<  
        Bind a specific MType call to a function or class method.

        The function must be of the form::

            def my_function_or_method(<self,> private_key, sender_id, msg_id,
                                      mtype, params, extra)

        where ``private_key`` is the client private-key, ``sender_id`` is the
        notification sender ID, ``msg_id`` is the Hub message-id, ``mtype`` is
        the message MType, ``params`` is the message parameter set (content of
        ``"samp.params"``) and ``extra`` is a dictionary containing any extra
        message map entry. The client is automatically declared subscribed to
        the MType by default.

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

        function : callable
            Application function to be used when ``mtype`` is received.

        declare : bool, optional
            Specify whether the client must be automatically declared as
            subscribed to the MType (see also
            :meth:`~astropy.samp.client.SAMPClient.declare_subscriptions`).

        metadata : dict, optional
            Dictionary containing additional metadata to declare associated
            with the MType subscribed to (see also
            :meth:`~astropy.samp.client.SAMPClient.declare_subscriptions`).
        u   Client not callable.N(   R   R"   Rh   R	   (   R7   R[   Rf   Rc   R:   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyRd   ร  s    "		c         C` s)   |  j  r | |  j | <n t d   d S(   uข  
        Bind a specific msg-tag response to a function or class method.

        The function must be of the form::

            def my_function_or_method(<self,> private_key, responder_id,
                                      msg_tag, response)

        where ``private_key`` is the client private-key, ``responder_id`` is
        the message responder ID, ``msg_tag`` is the message-tag provided at
        call time and ``response`` is the response received.

        Parameters
        ----------
        msg_tag : str
            Message-tag to be caught.

        function : callable
            Application function to be used when ``msg_tag`` is received.
        u   Client not callable.N(   R   R#   R	   (   R7   R`   Rf   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt   bind_receive_response๎  s    	c         C` s9   |  j  r) |  j | =| r5 |  j   q5 n t d   d S(   uฦ  
        Remove from the notifications binding table the specified MType and
        unsubscribe the client from it (if required).

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

        declare : bool
            Specify whether the client must be automatically declared as
            unsubscribed from the MType (see also
            :meth:`~astropy.samp.client.SAMPClient.declare_subscriptions`).
        u   Client not callable.N(   R   R   Rh   R	   (   R7   R[   Rc   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt   unbind_receive_notification  s
    	
c         C` s9   |  j  r) |  j | =| r5 |  j   q5 n t d   d S(   uพ  
        Remove from the calls binding table the specified MType and unsubscribe
        the client from it (if required).

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

        declare : bool
            Specify whether the client must be automatically declared as
            unsubscribed from the MType (see also
            :meth:`~astropy.samp.client.SAMPClient.declare_subscriptions`).
        u   Client not callable.N(   R   R"   Rh   R	   (   R7   R[   Rc   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt   unbind_receive_call  s
    	
c         C` s&   |  j  r |  j | =n t d   d S(   uธ   
        Remove from the responses binding table the specified message-tag.

        Parameters
        ----------
        msg_tag : str
            Message-tag to be removed.
        u   Client not callable.N(   R   R#   R	   (   R7   R`   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt   unbind_receive_response4  s    		c         C` s)   |  j  r |  j |  n t d   d S(   u  
        Declares the MTypes the client wishes to subscribe to, implicitly
        defined with the MType binding methods
        :meth:`~astropy.samp.client.SAMPClient.bind_receive_notification`
        and :meth:`~astropy.samp.client.SAMPClient.bind_receive_call`.

        An optional ``subscriptions`` map can be added to the final map passed
        to the :meth:`~astropy.samp.hub_proxy.SAMPHubProxy.declare_subscriptions`
        method.

        Parameters
        ----------
        subscriptions : dict, optional
            Dictionary containing the list of MTypes to subscribe to, with the
            same format of the ``subscriptions`` map passed to the
            :meth:`~astropy.samp.hub_proxy.SAMPHubProxy.declare_subscriptions`
            method.
        u   Client not callable.N(   R   Rh   R	   (   R7   t   subscriptions(    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt   declare_subscriptionsB  s    	c         C` s  |  j  j r๓ |  j d
 k	 r* t d   n  |  j  j |  j  j d  } | d d k re t d   n  | d d k r t d   n  | d |  _ | d |  _ | d |  _ |  j	 rห |  j
   |  j   n  |  j i  k r็ |  j   n  t |  _ n t d	   d
 S(   u6   
        Register the client to the SAMP Hub.
        u   Client already registeredu   samp.secretu   samp.self-idu    u:   Registration failed - samp.self-id was not set by the hub.u   samp.private-keyu>   Registration failed - samp.private-key was not set by the hub.u   samp.hub-idu<   Unable to register to the SAMP Hub. Hub proxy not connected.N(   R)   t   is_connectedR   R   R	   t   registert   lockfileR   R   R   t   _set_xmlrpc_callbackRh   R   t   declare_metadataR.   R   (   R7   t   result(    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyRp   Z  s$    	
c         C` sV   |  j  j rF t |  _ |  j  j |  j  d |  _ d |  _ d |  _ n t	 d   d S(   u:   
        Unregister the client from the SAMP Hub.
        u@   Unable to unregister from the SAMP Hub. Hub proxy not connected.N(
   R)   Ro   R   R   t
   unregisterR   R   R   R   R	   (   R7   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyRu   ~  s    			c         C` s;   |  j  j r7 |  j d  k	 r7 |  j  j |  j |  j  n  d  S(   N(   R)   Ro   R   R   t   set_xmlrpc_callbackR   (   R7   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyRr     s    c         C` sู   |  j  j rษ |  j d  k	 rษ i  } x5 |  j j   D]$ } t j |  j | d  | | <q1 Wx5 |  j j   D]$ } t j |  j | d  | | <qi W| rฐ | j	 t j |   n  |  j  j
 |  j |  n t d   d  S(   Ni   u[   Unable to declare subscriptions. Hub unreachable or not connected or client not registered.(   R)   Ro   R   R   R   t   keyst   copyt   deepcopyR"   t   updateRn   R	   (   R7   Rm   t   mtypes_dictR[   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyRh     s    ""c         C` sf   |  j  j rV |  j d k	 rV | d k	 r: |  j j |  n  |  j  j |  j |  j  n t d   d S(   u>  
        Declare the client application metadata supported.

        Parameters
        ----------
        metadata : dict, optional
            Dictionary containing the client application metadata as defined in
            the SAMP definition document. If omitted, then no metadata are
            declared.
        uV   Unable to declare metadata. Hub unreachable or not connected or client not registered.N(   R)   Ro   R   R   R   Rz   Rs   R	   (   R7   R:   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyRs   จ  s
    c         C` s   |  j  S(   uํ   
        Return the client private key used for the Standard Profile
        communications obtained at registration time (``samp.private-key``).

        Returns
        -------
        key : str
            Client private key.
        (   R   (   R7   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyRX   ผ  s    
c         C` s   |  j  S(   uณ   
        Return public client ID obtained at registration time
        (``samp.self-id``).

        Returns
        -------
        id : str
            Client public ID.
        (   R   (   R7   (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt   get_public_idศ  s    
N($   t   __name__t
   __module__t   __doc__R   R.   R?   RA   RE   t   propertyRF   RG   R@   R,   R    R!   R]   R2   R^   R3   Rb   R4   Rg   Re   Rd   Ri   Rj   Rk   Rl   Rn   Rp   Ru   Rr   Rh   Rs   RX   R|   (    (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyR      sB   !	C							 		#		$**+			$			(   t
   __future__R    R   R   R   Rx   RV   RH   R%   R*   RI   t    R   t   extern.six.moves.urllib.parseR   t	   constantsR   R   R)   R   t   errorsR	   R
   t   utilsR   R   t   standard_profileR   t   __all__t   objectR   (    (    (    s2   lib/python2.7/site-packages/astropy/samp/client.pyt   <module>   s   "	