예제 #1
0
파일: net.py 프로젝트: jobdiogenes/OpenSRF
class Network(JabberClient):
    def __init__(self, **args):
        self.isconnected = False

        # Create a unique jabber resource
        resource = args.get('resource') or 'python_client'
        resource += '_' + gethostname() + ':' + str(os.getpid()) + '_' + \
            threading.currentThread().getName().lower()
        self.jid = JID(args['username'], args['host'], resource)

        osrf.log.log_debug("initializing network with JID %s and host=%s, "
            "port=%s, username=%s" % (self.jid.as_utf8(), args['host'], \
            args['port'], args['username']))

        #initialize the superclass
        JabberClient.__init__(self, self.jid, args['password'], args['host'])
        self.queue = []

        self.receive_callback = None
        self.transport_error_msg = None

    def connect(self):
        JabberClient.connect(self)
        while not self.isconnected:
            stream = self.get_stream()
            act = stream.loop_iter(10)
            if not act:
                self.idle()

    def set_receive_callback(self, func):
        """The callback provided is called when a message is received.
        
            The only argument to the function is the received message. """
        self.receive_callback = func

    def session_started(self):
        osrf.log.log_info("Successfully connected to the opensrf network")
        self.authenticated()
        self.stream.set_message_handler("normal", self.message_received)
        self.stream.set_message_handler("error", self.error_received)
        self.isconnected = True

    def send(self, message):
        """Sends the provided network message."""
        osrf.log.log_internal("jabber sending to %s: %s" %
                              (message.recipient, message.body))
        message.sender = self.jid.as_utf8()
        msg = message.make_xmpp_msg()
        self.stream.send(msg)

    def error_received(self, stanza):
        self.transport_error_msg = NetworkMessage(stanza)
        osrf.log.log_error("XMPP error message received from %s" %
                           self.transport_error_msg.sender)

    def message_received(self, stanza):
        """Handler for received messages."""
        if stanza.get_type() == "headline":
            return True
        # check for errors
        osrf.log.log_internal("jabber received message from %s : %s" %
                              (stanza.get_from().as_utf8(), stanza.get_body()))
        self.queue.append(NetworkMessage(stanza))
        return True

    def stream_closed(self, stream):
        osrf.log.log_debug("XMPP Stream closing...")

    def stream_error(self, err):
        osrf.log.log_error("XMPP Stream error: condition: %s %r" %
                           (err.get_condition().name, err.serialize()))

    def disconnected(self):
        osrf.log.log_internal('XMPP Disconnected')

    def recv(self, timeout=120):
        """Attempts to receive a message from the network.

        timeout - max number of seconds to wait for a message.  
        If a message is received in 'timeout' seconds, the message is passed to 
        the receive_callback is called and True is returned.  Otherwise, false is
        returned.
        """

        forever = False
        if timeout < 0:
            forever = True
            timeout = None

        if len(self.queue) == 0:
            while (forever or timeout >= 0) and len(self.queue) == 0:
                starttime = time.time()

                stream = self.get_stream()
                if not stream:
                    raise XMPPNoConnection('We lost our server connection...')

                act = stream.loop_iter(timeout)
                endtime = time.time() - starttime

                if not forever:
                    timeout -= endtime

                osrf.log.log_internal("exiting stream loop after %s seconds. "
                                      "act=%s, queue size=%d" %
                                      (str(endtime), act, len(self.queue)))

                if self.transport_error_msg:
                    msg = self.transport_error_msg
                    self.transport_error_msg = None
                    raise XMPPNoRecipient(msg.sender)

                if not act:
                    self.idle()

        # if we've acquired a message, handle it
        msg = None
        if len(self.queue) > 0:
            msg = self.queue.pop(0)
            if self.receive_callback:
                self.receive_callback(msg)

        return msg

    def flush_inbound_data(self):
        ''' Read all pending inbound messages from the socket and discard them '''
        cb = self.receive_callback
        self.receive_callback = None
        while self.recv(0):
            pass
        self.receive_callback = cb
예제 #2
0
class Delay(StanzaPayloadObject):
    """
    Delayed delivery tag.

    Represents 'urn:xmpp:delay' (XEP-0203) element of a Jabber stanza.

    :Ivariables:
        - `delay_from`: the "from" value of the delay element
        - `reason`: the "reason" (content) of the delay element
        - `timestamp`: the UTC timestamp as naive datetime object
    """

    xml_element_name = "delay"
    xml_element_namespace = DELAY_NS

    _sort_order = 1
    _time_format = "%Y-%m-%dT%H:%M:%SZ"

    def __init__(self,
                 node_or_datetime,
                 delay_from=None,
                 reason=None,
                 utc=True):
        """
        Initialize the Delay object.

        :Parameters:
            - `node_or_datetime`: an XML node to parse or the timestamp.
            - `delay_from`: JID of the entity which adds the delay mark
              (when `node_or_datetime` is a timestamp).
            - `reason`: reason of the delay (when `node_or_datetime` is a
              timestamp).
            - `utc`: if `True` then the timestamp is assumed to be UTC,
              otherwise it is assumed to be local time.
        :Types:
            - `node_or_datetime`: `libxml2.xmlNode` or `datetime.datetime`
            - `delay_from`: `pyxmpp.JID`
            - `reason`: `unicode`
            - `utc`: `bool`"""
        if isinstance(node_or_datetime, libxml2.xmlNode):
            self.from_xml(node_or_datetime)
        else:
            if utc:
                self.timestamp = node_or_datetime
            else:
                self.timestamp = datetime_local_to_utc(node_or_datetime)
            self.delay_from = JID(delay_from)
            self.reason = unicode(reason)

    def from_xml(self, xmlnode):
        """Initialize Delay object from an XML node.

        :Parameters:
            - `xmlnode`: the jabber:x:delay XML element.
        :Types:
            - `xmlnode`: `libxml2.xmlNode`"""
        if xmlnode.type != "element":
            raise ValueError, "XML node is not a jabber:x:delay element (not an element)"
        ns = get_node_ns_uri(xmlnode)
        if ns and (ns != self.xml_element_namespace
                   or xmlnode.name != self.xml_element_name):
            raise ValueError, "XML node is not a " + self.xml_element_namespace + " element"
        stamp = xmlnode.prop("stamp")
        tm = _parse_ts(stamp)
        tm = tm[0:8] + (0, )
        self.timestamp = datetime.datetime.fromtimestamp(time.mktime(tm))
        delay_from = from_utf8(xmlnode.prop("from"))
        if delay_from:
            try:
                self.delay_from = JID(delay_from)
            except JIDError:
                raise JIDMalformedProtocolError, "Bad JID in the " + self.xml_element_namespace + " 'from' attribute"
        else:
            self.delay_from = None
        self.reason = from_utf8(xmlnode.getContent())

    def complete_xml_element(self, xmlnode, _unused):
        """Complete the XML node with `self` content.

        Should be overriden in classes derived from `StanzaPayloadObject`.

        :Parameters:
            - `xmlnode`: XML node with the element being built. It has already
              right name and namespace, but no attributes or content.
            - `_unused`: document to which the element belongs.
        :Types:
            - `xmlnode`: `libxml2.xmlNode`
            - `_unused`: `libxml2.xmlDoc`"""
        tm = self.timestamp.strftime(self._time_format)
        xmlnode.setProp("stamp", tm)
        if self.delay_from:
            xmlnode.setProp("from", self.delay_from.as_utf8())
        if self.reason:
            xmlnode.setContent(to_utf8(self.reason))

    def get_datetime_local(self):
        """Get the timestamp as a local time.

        :return: the timestamp of the delay element represented in the local
          timezone.
        :returntype: `datetime.datetime`"""
        r = datetime_utc_to_local(self.timestamp)
        return r

    def get_datetime_utc(self):
        """Get the timestamp as a UTC.

        :return: the timestamp of the delay element represented in UTC.
        :returntype: `datetime.datetime`"""
        return self.timestamp

    def __str__(self):
        n = self.as_xml()
        r = n.serialize()
        n.freeNode()
        return r

    def __cmp__(self, other):
        return cmp((self._sort_order, self.timestamp),
                   (other._sort_order, other.timestamp))
예제 #3
0
파일: stanza.py 프로젝트: sgricci/digsby
    def __init__(self, name_or_xmlnode, from_jid=None, to_jid=None,
            stanza_type=None, stanza_id=None, error=None, error_cond=None,
            stream = None):
        """Initialize a Stanza object.

        :Parameters:
            - `name_or_xmlnode`: XML node to be wrapped into the Stanza object
              or other Presence object to be copied. If not given then new
              presence stanza is created using following parameters.
            - `from_jid`: sender JID.
            - `to_jid`: recipient JID.
            - `stanza_type`: staza type: one of: "get", "set", "result" or "error".
            - `stanza_id`: stanza id -- value of stanza's "id" attribute. If
              not given, then unique for the session value is generated.
            - `error`: error object. Ignored if `stanza_type` is not "error".
            - `error_cond`: error condition name. Ignored if `stanza_type` is not
              "error" or `error` is not None.
        :Types:
            - `name_or_xmlnode`: `unicode` or `libxml2.xmlNode` or `Stanza`
            - `from_jid`: `JID`
            - `to_jid`: `JID`
            - `stanza_type`: `unicode`
            - `stanza_id`: `unicode`
            - `error`: `pyxmpp.error.StanzaErrorNode`
            - `error_cond`: `unicode`"""
        self._error=None
        self.xmlnode=None
        if isinstance(name_or_xmlnode,Stanza):
            self.xmlnode=name_or_xmlnode.xmlnode.copyNode(1)
            common_doc.addChild(self.xmlnode)
        elif isinstance(name_or_xmlnode,libxml2.xmlNode):
            self.xmlnode=name_or_xmlnode.docCopyNode(common_doc,1)
            common_doc.addChild(self.xmlnode)
            try:
                ns = self.xmlnode.ns()
            except libxml2.treeError:
                ns = None
            if not ns or not ns.name:
                xmlextra.replace_ns(self.xmlnode, ns, common_ns)
        else:
            self.xmlnode=common_doc.newChild(common_ns,name_or_xmlnode,None)

        if from_jid is not None:
            if not isinstance(from_jid,JID):
                from_jid=JID(from_jid)
            self.xmlnode.setProp("from",from_jid.as_utf8())

        if to_jid is not None:
            if not isinstance(to_jid,JID):
                to_jid=JID(to_jid)
            self.xmlnode.setProp("to",to_jid.as_utf8())

        if stanza_type:
            self.xmlnode.setProp("type",stanza_type)

        if stanza_id:
            self.xmlnode.setProp("id",stanza_id)

        if self.get_type()=="error":
            from pyxmpp.error import StanzaErrorNode
            if error:
                self._error=StanzaErrorNode(error,parent=self.xmlnode,copy=1)
            elif error_cond:
                self._error=StanzaErrorNode(error_cond,parent=self.xmlnode)
        self.stream = stream
예제 #4
0
class Network(JabberClient):
    def __init__(self, **args):
        self.isconnected = False

        # Create a unique jabber resource
        resource = args.get('resource') or 'python_client'
        resource += '_' + gethostname() + ':' + str(os.getpid()) + '_' + \
            threading.currentThread().getName().lower()
        self.jid = JID(args['username'], args['host'], resource)

        osrf.log.log_debug("initializing network with JID %s and host=%s, "
            "port=%s, username=%s" % (self.jid.as_utf8(), args['host'], \
            args['port'], args['username']))

        #initialize the superclass
        JabberClient.__init__(self, self.jid, args['password'], args['host'])
        self.queue = []

        self.receive_callback = None
        self.transport_error_msg = None

    def connect(self):
        JabberClient.connect(self)
        while not self.isconnected:
            stream = self.get_stream()
            act = stream.loop_iter(10)
            if not act:
                self.idle()

    def set_receive_callback(self, func):
        """The callback provided is called when a message is received.
        
            The only argument to the function is the received message. """
        self.receive_callback = func

    def session_started(self):
        osrf.log.log_info("Successfully connected to the opensrf network")
        self.authenticated()
        self.stream.set_message_handler("normal", self.message_received)
        self.stream.set_message_handler("error", self.error_received)
        self.isconnected = True

    def send(self, message):
        """Sends the provided network message."""
        osrf.log.log_internal("jabber sending to %s: %s" % (message.recipient, message.body))
        message.sender = self.jid.as_utf8()
        msg = message.make_xmpp_msg()
        self.stream.send(msg)

    def error_received(self, stanza):
        self.transport_error_msg = NetworkMessage(stanza)
        osrf.log.log_error("XMPP error message received from %s" % self.transport_error_msg.sender)
    
    def message_received(self, stanza):
        """Handler for received messages."""
        if stanza.get_type()=="headline":
            return True
        # check for errors
        osrf.log.log_internal("jabber received message from %s : %s" 
            % (stanza.get_from().as_utf8(), stanza.get_body()))
        self.queue.append(NetworkMessage(stanza))
        return True

    def stream_closed(self, stream):
        osrf.log.log_debug("XMPP Stream closing...")

    def stream_error(self, err):
        osrf.log.log_error("XMPP Stream error: condition: %s %r"
            % (err.get_condition().name,err.serialize()))

    def disconnected(self):
        osrf.log.log_internal('XMPP Disconnected')

    def recv(self, timeout=120):
        """Attempts to receive a message from the network.

        timeout - max number of seconds to wait for a message.  
        If a message is received in 'timeout' seconds, the message is passed to 
        the receive_callback is called and True is returned.  Otherwise, false is
        returned.
        """

        forever = False
        if timeout < 0:
            forever = True
            timeout = None

        if len(self.queue) == 0:
            while (forever or timeout >= 0) and len(self.queue) == 0:
                starttime = time.time()

                stream = self.get_stream()
                if not stream:
                   raise XMPPNoConnection('We lost our server connection...') 

                act = stream.loop_iter(timeout)
                endtime = time.time() - starttime

                if not forever:
                    timeout -= endtime

                osrf.log.log_internal("exiting stream loop after %s seconds. "
                    "act=%s, queue size=%d" % (str(endtime), act, len(self.queue)))

                if self.transport_error_msg:
                    msg = self.transport_error_msg
                    self.transport_error_msg = None
                    raise XMPPNoRecipient(msg.sender)

                if not act:
                    self.idle()

        # if we've acquired a message, handle it
        msg = None
        if len(self.queue) > 0:
            msg = self.queue.pop(0)
            if self.receive_callback:
                self.receive_callback(msg)

        return msg


    def flush_inbound_data(self):
        ''' Read all pending inbound messages from the socket and discard them '''
        cb = self.receive_callback
        self.receive_callback = None
        while self.recv(0): pass 
        self.receive_callback = cb
예제 #5
0
파일: delay.py 프로젝트: Jajcus/pyxmpp
class Delay(StanzaPayloadObject):
    """
    Delayed delivery tag.

    Represents 'urn:xmpp:delay' (XEP-0203) element of a Jabber stanza.

    :Ivariables:
        - `delay_from`: the "from" value of the delay element
        - `reason`: the "reason" (content) of the delay element
        - `timestamp`: the UTC timestamp as naive datetime object
    """

    xml_element_name = "delay"
    xml_element_namespace = DELAY_NS

    _sort_order = 1
    _time_format = "%Y-%m-%dT%H:%M:%SZ"

    def __init__(self,node_or_datetime,delay_from=None,reason=None,utc=True):
        """
        Initialize the Delay object.

        :Parameters:
            - `node_or_datetime`: an XML node to parse or the timestamp.
            - `delay_from`: JID of the entity which adds the delay mark
              (when `node_or_datetime` is a timestamp).
            - `reason`: reason of the delay (when `node_or_datetime` is a
              timestamp).
            - `utc`: if `True` then the timestamp is assumed to be UTC,
              otherwise it is assumed to be local time.
        :Types:
            - `node_or_datetime`: `libxml2.xmlNode` or `datetime.datetime`
            - `delay_from`: `pyxmpp.JID`
            - `reason`: `unicode`
            - `utc`: `bool`"""
        if isinstance(node_or_datetime,libxml2.xmlNode):
            self.from_xml(node_or_datetime)
        else:
            if utc:
                self.timestamp=node_or_datetime
            else:
                self.timestamp=datetime_local_to_utc(node_or_datetime)
            self.delay_from=JID(delay_from)
            self.reason=unicode(reason)

    def from_xml(self,xmlnode):
        """Initialize Delay object from an XML node.

        :Parameters:
            - `xmlnode`: the jabber:x:delay XML element.
        :Types:
            - `xmlnode`: `libxml2.xmlNode`"""
        if xmlnode.type!="element":
            raise ValueError,"XML node is not a jabber:x:delay element (not an element)"
        ns=get_node_ns_uri(xmlnode)
        if ns and (ns != self.xml_element_namespace
                or xmlnode.name != self.xml_element_name):
            raise ValueError,"XML node is not a " + self.xml_element_namespace + " element"
        stamp=xmlnode.prop("stamp")
        tm = _parse_ts(stamp)
        tm=tm[0:8]+(0,)
        self.timestamp=datetime.datetime.fromtimestamp(time.mktime(tm))
        delay_from=from_utf8(xmlnode.prop("from"))
        if delay_from:
            try:
                self.delay_from = JID(delay_from)
            except JIDError:
                raise JIDMalformedProtocolError, "Bad JID in the " + self.xml_element_namespace + " 'from' attribute"
        else:
            self.delay_from = None
        self.reason = from_utf8(xmlnode.getContent())

    def complete_xml_element(self, xmlnode, _unused):
        """Complete the XML node with `self` content.

        Should be overriden in classes derived from `StanzaPayloadObject`.

        :Parameters:
            - `xmlnode`: XML node with the element being built. It has already
              right name and namespace, but no attributes or content.
            - `_unused`: document to which the element belongs.
        :Types:
            - `xmlnode`: `libxml2.xmlNode`
            - `_unused`: `libxml2.xmlDoc`"""
        tm=self.timestamp.strftime(self._time_format)
        xmlnode.setProp("stamp",tm)
        if self.delay_from:
            xmlnode.setProp("from",self.delay_from.as_utf8())
        if self.reason:
            xmlnode.setContent(to_utf8(self.reason))

    def get_datetime_local(self):
        """Get the timestamp as a local time.

        :return: the timestamp of the delay element represented in the local
          timezone.
        :returntype: `datetime.datetime`"""
        r=datetime_utc_to_local(self.timestamp)
        return r

    def get_datetime_utc(self):
        """Get the timestamp as a UTC.

        :return: the timestamp of the delay element represented in UTC.
        :returntype: `datetime.datetime`"""
        return self.timestamp

    def __str__(self):
        n=self.as_xml()
        r=n.serialize()
        n.freeNode()
        return r

    def __cmp__(self, other):
        return cmp((self._sort_order, self.timestamp),
                    (other._sort_order, other.timestamp))