mirror of
https://github.com/correl/SleekXMPP.git
synced 2024-11-24 03:00:15 +00:00
Merge branch 'develop' of github.com:fritzy/SleekXMPP into roster
This commit is contained in:
commit
58b95e4ae4
11 changed files with 318 additions and 21 deletions
|
@ -105,6 +105,10 @@ if __name__ == '__main__':
|
||||||
logging.basicConfig(level=opts.loglevel,
|
logging.basicConfig(level=opts.loglevel,
|
||||||
format='%(levelname)-8s %(message)s')
|
format='%(levelname)-8s %(message)s')
|
||||||
|
|
||||||
|
if None in [opts.jid, opts.password]:
|
||||||
|
optp.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# Setup the EchoBot and register plugins. Note that while plugins may
|
# Setup the EchoBot and register plugins. Note that while plugins may
|
||||||
# have interdependencies, the order in which you register them does
|
# have interdependencies, the order in which you register them does
|
||||||
# not matter.
|
# not matter.
|
||||||
|
|
186
examples/muc.py
Executable file
186
examples/muc.py
Executable file
|
@ -0,0 +1,186 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2010 Nathanael C. Fritz
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
import sleekxmpp
|
||||||
|
|
||||||
|
# Python versions before 3.0 do not use UTF-8 encoding
|
||||||
|
# by default. To ensure that Unicode is handled properly
|
||||||
|
# throughout SleekXMPP, we will set the default encoding
|
||||||
|
# ourselves to UTF-8.
|
||||||
|
if sys.version_info < (3, 0):
|
||||||
|
reload(sys)
|
||||||
|
sys.setdefaultencoding('utf8')
|
||||||
|
|
||||||
|
|
||||||
|
class MUCBot(sleekxmpp.ClientXMPP):
|
||||||
|
|
||||||
|
"""
|
||||||
|
A simple SleekXMPP bot that will greets those
|
||||||
|
who enter the room, and acknowledge any messages
|
||||||
|
that mentions the bot's nickname.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, jid, password, room, nick):
|
||||||
|
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||||
|
|
||||||
|
self.room = room
|
||||||
|
self.nick = nick
|
||||||
|
|
||||||
|
# The session_start event will be triggered when
|
||||||
|
# the bot establishes its connection with the server
|
||||||
|
# and the XML streams are ready for use. We want to
|
||||||
|
# listen for this event so that we we can intialize
|
||||||
|
# our roster.
|
||||||
|
self.add_event_handler("session_start", self.start)
|
||||||
|
|
||||||
|
# The groupchat_message event is triggered whenever a message
|
||||||
|
# stanza is received from any chat room. If you also also
|
||||||
|
# register a handler for the 'message' event, MUC messages
|
||||||
|
# will be processed by both handlers.
|
||||||
|
self.add_event_handler("groupchat_message", self.muc_message)
|
||||||
|
|
||||||
|
# The groupchat_presence event is triggered whenever a
|
||||||
|
# presence stanza is received from any chat room, including
|
||||||
|
# any presences you send yourself. To limit event handling
|
||||||
|
# to a single room, use the events muc::room@server::presence,
|
||||||
|
# muc::room@server::got_online, or muc::room@server::got_offline.
|
||||||
|
self.add_event_handler("muc::%s::got_online" % self.room,
|
||||||
|
self.muc_online)
|
||||||
|
|
||||||
|
|
||||||
|
def start(self, event):
|
||||||
|
"""
|
||||||
|
Process the session_start event.
|
||||||
|
|
||||||
|
Typical actions for the session_start event are
|
||||||
|
requesting the roster and broadcasting an intial
|
||||||
|
presence stanza.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
event -- An empty dictionary. The session_start
|
||||||
|
event does not provide any additional
|
||||||
|
data.
|
||||||
|
"""
|
||||||
|
self.getRoster()
|
||||||
|
self.sendPresence()
|
||||||
|
self.plugin['xep_0045'].joinMUC(self.room,
|
||||||
|
self.nick,
|
||||||
|
# If a room password is needed, use:
|
||||||
|
# password=the_room_password,
|
||||||
|
wait=True)
|
||||||
|
|
||||||
|
def muc_message(self, msg):
|
||||||
|
"""
|
||||||
|
Process incoming message stanzas from any chat room. Be aware
|
||||||
|
that if you also have any handlers for the 'message' event,
|
||||||
|
message stanzas may be processed by both handlers, so check
|
||||||
|
the 'type' attribute when using a 'message' event handler.
|
||||||
|
|
||||||
|
Whenever the bot's nickname is mentioned, respond to
|
||||||
|
the message.
|
||||||
|
|
||||||
|
IMPORTANT: Always check that a message is not from yourself,
|
||||||
|
otherwise you will create an infinite loop responding
|
||||||
|
to your own messages.
|
||||||
|
|
||||||
|
This handler will reply to messages that mention
|
||||||
|
the bot's nickname.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
msg -- The received message stanza. See the documentation
|
||||||
|
for stanza objects and the Message stanza to see
|
||||||
|
how it may be used.
|
||||||
|
"""
|
||||||
|
if msg['mucnick'] != self.nick and self.nick in msg['body']:
|
||||||
|
self.send_message(mto=msg['from'].bare,
|
||||||
|
mbody="I heard that, %s." % msg['mucnick'],
|
||||||
|
mtype='groupchat')
|
||||||
|
|
||||||
|
def muc_online(self, presence):
|
||||||
|
"""
|
||||||
|
Process a presence stanza from a chat room. In this case,
|
||||||
|
presences from users that have just come online are
|
||||||
|
handled by sending a welcome message that includes
|
||||||
|
the user's nickname and role in the room.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
presence -- The received presence stanza. See the
|
||||||
|
documentation for the Presence stanza
|
||||||
|
to see how else it may be used.
|
||||||
|
"""
|
||||||
|
if presence['muc']['nick'] != self.nick:
|
||||||
|
self.send_message(mto=presence['from'].bare,
|
||||||
|
mbody="Hello, %s %s" % (presence['muc']['role'],
|
||||||
|
presence['muc']['nick']),
|
||||||
|
mtype='groupchat')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Setup the command line arguments.
|
||||||
|
optp = OptionParser()
|
||||||
|
|
||||||
|
# Output verbosity options.
|
||||||
|
optp.add_option('-q', '--quiet', help='set logging to ERROR',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.ERROR, default=logging.INFO)
|
||||||
|
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=logging.DEBUG, default=logging.INFO)
|
||||||
|
optp.add_option('-v', '--verbose', help='set logging to COMM',
|
||||||
|
action='store_const', dest='loglevel',
|
||||||
|
const=5, default=logging.INFO)
|
||||||
|
|
||||||
|
# JID and password options.
|
||||||
|
optp.add_option("-j", "--jid", dest="jid",
|
||||||
|
help="JID to use")
|
||||||
|
optp.add_option("-p", "--password", dest="password",
|
||||||
|
help="password to use")
|
||||||
|
optp.add_option("-r", "--room", dest="room",
|
||||||
|
help="MUC room to join")
|
||||||
|
optp.add_option("-n", "--nick", dest="nick",
|
||||||
|
help="MUC nickname")
|
||||||
|
|
||||||
|
opts, args = optp.parse_args()
|
||||||
|
|
||||||
|
# Setup logging.
|
||||||
|
logging.basicConfig(level=opts.loglevel,
|
||||||
|
format='%(levelname)-8s %(message)s')
|
||||||
|
|
||||||
|
if None in [opts.jid, opts.password, opts.room, opts.nick]:
|
||||||
|
optp.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Setup the MUCBot and register plugins. Note that while plugins may
|
||||||
|
# have interdependencies, the order in which you register them does
|
||||||
|
# not matter.
|
||||||
|
xmpp = MUCBot(opts.jid, opts.password, opts.room, opts.nick)
|
||||||
|
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||||
|
xmpp.register_plugin('xep_0045') # Multi-User Chat
|
||||||
|
xmpp.register_plugin('xep_0199') # XMPP Ping
|
||||||
|
|
||||||
|
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||||
|
if xmpp.connect():
|
||||||
|
# If you do not have the pydns library installed, you will need
|
||||||
|
# to manually specify the name of the server if it does not match
|
||||||
|
# the one in the JID. For example, to use Google Talk you would
|
||||||
|
# need to use:
|
||||||
|
#
|
||||||
|
# if xmpp.connect(('talk.google.com', 5222)):
|
||||||
|
# ...
|
||||||
|
xmpp.process(threaded=False)
|
||||||
|
print("Done")
|
||||||
|
else:
|
||||||
|
print("Unable to connect.")
|
|
@ -383,7 +383,7 @@ class ClientXMPP(BaseXMPP):
|
||||||
self.set_jid(response.xml.find('{%s}bind/{%s}jid' % (bind_ns,
|
self.set_jid(response.xml.find('{%s}bind/{%s}jid' % (bind_ns,
|
||||||
bind_ns)).text)
|
bind_ns)).text)
|
||||||
self.bound = True
|
self.bound = True
|
||||||
log.info("Node set to: %s" % self.boundjid.fulljid)
|
log.info("Node set to: %s" % self.boundjid.full)
|
||||||
session_ns = 'urn:ietf:params:xml:ns:xmpp-session'
|
session_ns = 'urn:ietf:params:xml:ns:xmpp-session'
|
||||||
if "{%s}session" % session_ns not in self.features or self.bindfail:
|
if "{%s}session" % session_ns not in self.features or self.bindfail:
|
||||||
log.debug("Established Session")
|
log.debug("Established Session")
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
from sleekxmpp.stanza import Error
|
from sleekxmpp.stanza import Error
|
||||||
from sleekxmpp.stanza.rootstanza import RootStanza
|
from sleekxmpp.stanza.rootstanza import RootStanza
|
||||||
from sleekxmpp.xmlstream import RESPONSE_TIMEOUT, StanzaBase, ET
|
from sleekxmpp.xmlstream import StanzaBase, ET
|
||||||
from sleekxmpp.xmlstream.handler import Waiter
|
from sleekxmpp.xmlstream.handler import Waiter
|
||||||
from sleekxmpp.xmlstream.matcher import MatcherId
|
from sleekxmpp.xmlstream.matcher import MatcherId
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ class Iq(RootStanza):
|
||||||
StanzaBase.reply(self)
|
StanzaBase.reply(self)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def send(self, block=True, timeout=RESPONSE_TIMEOUT):
|
def send(self, block=True, timeout=None):
|
||||||
"""
|
"""
|
||||||
Send an <iq> stanza over the XML stream.
|
Send an <iq> stanza over the XML stream.
|
||||||
|
|
||||||
|
@ -174,6 +174,8 @@ class Iq(RootStanza):
|
||||||
before exiting the send call if blocking is used.
|
before exiting the send call if blocking is used.
|
||||||
Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT
|
Defaults to sleekxmpp.xmlstream.RESPONSE_TIMEOUT
|
||||||
"""
|
"""
|
||||||
|
if timeout is None:
|
||||||
|
timeout = self.stream.response_timeout
|
||||||
if block and self['type'] in ('get', 'set'):
|
if block and self['type'] in ('get', 'set'):
|
||||||
waitfor = Waiter('IqWait_%s' % self['id'], MatcherId(self['id']))
|
waitfor = Waiter('IqWait_%s' % self['id'], MatcherId(self['id']))
|
||||||
self.stream.registerHandler(waitfor)
|
self.stream.registerHandler(waitfor)
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import socket
|
import socket
|
||||||
|
import threading
|
||||||
try:
|
try:
|
||||||
import queue
|
import queue
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -40,6 +41,8 @@ class TestLiveSocket(object):
|
||||||
self.recv_buffer = []
|
self.recv_buffer = []
|
||||||
self.recv_queue = queue.Queue()
|
self.recv_queue = queue.Queue()
|
||||||
self.send_queue = queue.Queue()
|
self.send_queue = queue.Queue()
|
||||||
|
self.send_queue_lock = threading.Lock()
|
||||||
|
self.recv_queue_lock = threading.Lock()
|
||||||
self.is_live = True
|
self.is_live = True
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
|
@ -108,7 +111,8 @@ class TestLiveSocket(object):
|
||||||
Placeholders. Same as for socket.recv.
|
Placeholders. Same as for socket.recv.
|
||||||
"""
|
"""
|
||||||
data = self.socket.recv(*args, **kwargs)
|
data = self.socket.recv(*args, **kwargs)
|
||||||
self.recv_queue.put(data)
|
with self.recv_queue_lock:
|
||||||
|
self.recv_queue.put(data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def send(self, data):
|
def send(self, data):
|
||||||
|
@ -120,7 +124,8 @@ class TestLiveSocket(object):
|
||||||
Arguments:
|
Arguments:
|
||||||
data -- String value to write.
|
data -- String value to write.
|
||||||
"""
|
"""
|
||||||
self.send_queue.put(data)
|
with self.send_queue_lock:
|
||||||
|
self.send_queue.put(data)
|
||||||
self.socket.send(data)
|
self.socket.send(data)
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
@ -143,3 +148,15 @@ class TestLiveSocket(object):
|
||||||
Placeholders, same as socket.recv()
|
Placeholders, same as socket.recv()
|
||||||
"""
|
"""
|
||||||
return self.recv(*args, **kwargs)
|
return self.recv(*args, **kwargs)
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
"""
|
||||||
|
Empty the send queue, typically done once the session has started to
|
||||||
|
remove the feature negotiation and log in stanzas.
|
||||||
|
"""
|
||||||
|
with self.send_queue_lock:
|
||||||
|
for i in range(0, self.send_queue.qsize()):
|
||||||
|
self.send_queue.get(block=False)
|
||||||
|
with self.recv_queue_lock:
|
||||||
|
for i in range(0, self.recv_queue.qsize()):
|
||||||
|
self.recv_queue.get(block=False)
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
try:
|
||||||
|
import Queue as queue
|
||||||
|
except:
|
||||||
|
import queue
|
||||||
|
|
||||||
import sleekxmpp
|
import sleekxmpp
|
||||||
from sleekxmpp import ClientXMPP, ComponentXMPP
|
from sleekxmpp import ClientXMPP, ComponentXMPP
|
||||||
|
@ -219,7 +223,10 @@ class SleekTest(unittest.TestCase):
|
||||||
"Stanza:\n%s" % str(stanza))
|
"Stanza:\n%s" % str(stanza))
|
||||||
else:
|
else:
|
||||||
stanza_class = stanza.__class__
|
stanza_class = stanza.__class__
|
||||||
xml = self.parse_xml(criteria)
|
if isinstance(criteria, str):
|
||||||
|
xml = self.parse_xml(criteria)
|
||||||
|
else:
|
||||||
|
xml = criteria.xml
|
||||||
|
|
||||||
# Ensure that top level namespaces are used, even if they
|
# Ensure that top level namespaces are used, even if they
|
||||||
# were not provided.
|
# were not provided.
|
||||||
|
@ -305,6 +312,10 @@ class SleekTest(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unknown XMPP connection mode.")
|
raise ValueError("Unknown XMPP connection mode.")
|
||||||
|
|
||||||
|
# We will use this to wait for the session_start event
|
||||||
|
# for live connections.
|
||||||
|
skip_queue = queue.Queue()
|
||||||
|
|
||||||
if socket == 'mock':
|
if socket == 'mock':
|
||||||
self.xmpp.set_socket(TestSocket())
|
self.xmpp.set_socket(TestSocket())
|
||||||
|
|
||||||
|
@ -319,6 +330,10 @@ class SleekTest(unittest.TestCase):
|
||||||
self.xmpp.socket.recv_data(header)
|
self.xmpp.socket.recv_data(header)
|
||||||
elif socket == 'live':
|
elif socket == 'live':
|
||||||
self.xmpp.socket_class = TestLiveSocket
|
self.xmpp.socket_class = TestLiveSocket
|
||||||
|
def wait_for_session(x):
|
||||||
|
self.xmpp.socket.clear()
|
||||||
|
skip_queue.put('started')
|
||||||
|
self.xmpp.add_event_handler('session_start', wait_for_session)
|
||||||
self.xmpp.connect()
|
self.xmpp.connect()
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unknown socket type.")
|
raise ValueError("Unknown socket type.")
|
||||||
|
@ -326,10 +341,13 @@ class SleekTest(unittest.TestCase):
|
||||||
self.xmpp.register_plugins()
|
self.xmpp.register_plugins()
|
||||||
self.xmpp.process(threaded=True)
|
self.xmpp.process(threaded=True)
|
||||||
if skip:
|
if skip:
|
||||||
# Clear startup stanzas
|
if socket != 'live':
|
||||||
self.xmpp.socket.next_sent(timeout=1)
|
# Clear startup stanzas
|
||||||
if mode == 'component':
|
|
||||||
self.xmpp.socket.next_sent(timeout=1)
|
self.xmpp.socket.next_sent(timeout=1)
|
||||||
|
if mode == 'component':
|
||||||
|
self.xmpp.socket.next_sent(timeout=1)
|
||||||
|
else:
|
||||||
|
skip_queue.get(block=True, timeout=10)
|
||||||
|
|
||||||
def make_header(self, sto='',
|
def make_header(self, sto='',
|
||||||
sfrom='',
|
sfrom='',
|
||||||
|
@ -599,11 +617,12 @@ class SleekTest(unittest.TestCase):
|
||||||
Defaults to the value of self.match_method.
|
Defaults to the value of self.match_method.
|
||||||
"""
|
"""
|
||||||
sent = self.xmpp.socket.next_sent(timeout)
|
sent = self.xmpp.socket.next_sent(timeout)
|
||||||
if isinstance(data, str):
|
if sent is None:
|
||||||
xml = self.parse_xml(data)
|
return False
|
||||||
self.fix_namespaces(xml, 'jabber:client')
|
xml = self.parse_xml(sent)
|
||||||
data = self.xmpp._build_stanza(xml, 'jabber:client')
|
self.fix_namespaces(xml, 'jabber:client')
|
||||||
self.check(data, sent,
|
sent = self.xmpp._build_stanza(xml, 'jabber:client')
|
||||||
|
self.check(sent, data,
|
||||||
method=method,
|
method=method,
|
||||||
defaults=defaults,
|
defaults=defaults,
|
||||||
use_values=use_values)
|
use_values=use_values)
|
||||||
|
|
|
@ -12,7 +12,7 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import Queue as queue
|
import Queue as queue
|
||||||
|
|
||||||
from sleekxmpp.xmlstream import StanzaBase, RESPONSE_TIMEOUT
|
from sleekxmpp.xmlstream import StanzaBase
|
||||||
from sleekxmpp.xmlstream.handler.base import BaseHandler
|
from sleekxmpp.xmlstream.handler.base import BaseHandler
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ class Waiter(BaseHandler):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def wait(self, timeout=RESPONSE_TIMEOUT):
|
def wait(self, timeout=None):
|
||||||
"""
|
"""
|
||||||
Block an event handler while waiting for a stanza to arrive.
|
Block an event handler while waiting for a stanza to arrive.
|
||||||
|
|
||||||
|
@ -84,6 +84,9 @@ class Waiter(BaseHandler):
|
||||||
arrive. Defaults to the global default timeout
|
arrive. Defaults to the global default timeout
|
||||||
value sleekxmpp.xmlstream.RESPONSE_TIMEOUT.
|
value sleekxmpp.xmlstream.RESPONSE_TIMEOUT.
|
||||||
"""
|
"""
|
||||||
|
if timeout is None:
|
||||||
|
timeout = self.stream.response_timeout
|
||||||
|
|
||||||
try:
|
try:
|
||||||
stanza = self._payload.get(True, timeout)
|
stanza = self._payload.get(True, timeout)
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
|
|
|
@ -121,3 +121,6 @@ class JID(object):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Use the full JID as the string value."""
|
"""Use the full JID as the string value."""
|
||||||
return self.full
|
return self.full
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self)
|
||||||
|
|
|
@ -25,6 +25,8 @@ except ImportError:
|
||||||
from sleekxmpp.thirdparty.statemachine import StateMachine
|
from sleekxmpp.thirdparty.statemachine import StateMachine
|
||||||
from sleekxmpp.xmlstream import Scheduler, tostring
|
from sleekxmpp.xmlstream import Scheduler, tostring
|
||||||
from sleekxmpp.xmlstream.stanzabase import StanzaBase, ET
|
from sleekxmpp.xmlstream.stanzabase import StanzaBase, ET
|
||||||
|
from sleekxmpp.xmlstream.handler import Waiter, XMLCallback
|
||||||
|
from sleekxmpp.xmlstream.matcher import MatchXMLMask
|
||||||
|
|
||||||
# In Python 2.x, file socket objects are broken. A patched socket
|
# In Python 2.x, file socket objects are broken. A patched socket
|
||||||
# wrapper is provided for this case in filesocket.py.
|
# wrapper is provided for this case in filesocket.py.
|
||||||
|
@ -162,6 +164,8 @@ class XMLStream(object):
|
||||||
self.ssl_support = SSL_SUPPORT
|
self.ssl_support = SSL_SUPPORT
|
||||||
self.ssl_version = ssl.PROTOCOL_TLSv1
|
self.ssl_version = ssl.PROTOCOL_TLSv1
|
||||||
|
|
||||||
|
self.response_timeout = RESPONSE_TIMEOUT
|
||||||
|
|
||||||
self.state = StateMachine(('disconnected', 'connected'))
|
self.state = StateMachine(('disconnected', 'connected'))
|
||||||
self.state._set_state('disconnected')
|
self.state._set_state('disconnected')
|
||||||
|
|
||||||
|
@ -458,8 +462,6 @@ class XMLStream(object):
|
||||||
"""
|
"""
|
||||||
# To prevent circular dependencies, we must load the matcher
|
# To prevent circular dependencies, we must load the matcher
|
||||||
# and handler classes here.
|
# and handler classes here.
|
||||||
from sleekxmpp.xmlstream.matcher import MatchXMLMask
|
|
||||||
from sleekxmpp.xmlstream.handler import XMLCallback
|
|
||||||
|
|
||||||
if name is None:
|
if name is None:
|
||||||
name = 'add_handler_%s' % self.getNewId()
|
name = 'add_handler_%s' % self.getNewId()
|
||||||
|
@ -606,7 +608,7 @@ class XMLStream(object):
|
||||||
"""
|
"""
|
||||||
return xml
|
return xml
|
||||||
|
|
||||||
def send(self, data, mask=None, timeout=RESPONSE_TIMEOUT):
|
def send(self, data, mask=None, timeout=None):
|
||||||
"""
|
"""
|
||||||
A wrapper for send_raw for sending stanza objects.
|
A wrapper for send_raw for sending stanza objects.
|
||||||
|
|
||||||
|
@ -621,6 +623,9 @@ class XMLStream(object):
|
||||||
timeout -- Time in seconds to wait for a response before
|
timeout -- Time in seconds to wait for a response before
|
||||||
continuing. Defaults to RESPONSE_TIMEOUT.
|
continuing. Defaults to RESPONSE_TIMEOUT.
|
||||||
"""
|
"""
|
||||||
|
if timeout is None:
|
||||||
|
timeout = self.response_timeout
|
||||||
|
|
||||||
if hasattr(mask, 'xml'):
|
if hasattr(mask, 'xml'):
|
||||||
mask = mask.xml
|
mask = mask.xml
|
||||||
data = str(data)
|
data = str(data)
|
||||||
|
@ -643,7 +648,7 @@ class XMLStream(object):
|
||||||
self.send_queue.put(data)
|
self.send_queue.put(data)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def send_xml(self, data, mask=None, timeout=RESPONSE_TIMEOUT):
|
def send_xml(self, data, mask=None, timeout=None):
|
||||||
"""
|
"""
|
||||||
Send an XML object on the stream, and optionally wait
|
Send an XML object on the stream, and optionally wait
|
||||||
for a response.
|
for a response.
|
||||||
|
@ -657,6 +662,8 @@ class XMLStream(object):
|
||||||
timeout -- Time in seconds to wait for a response before
|
timeout -- Time in seconds to wait for a response before
|
||||||
continuing. Defaults to RESPONSE_TIMEOUT.
|
continuing. Defaults to RESPONSE_TIMEOUT.
|
||||||
"""
|
"""
|
||||||
|
if timeout is None:
|
||||||
|
timeout = self.response_timeout
|
||||||
return self.send(tostring(data), mask, timeout)
|
return self.send(tostring(data), mask, timeout)
|
||||||
|
|
||||||
def process(self, threaded=True):
|
def process(self, threaded=True):
|
||||||
|
|
57
tests/live_multiple_streams.py
Normal file
57
tests/live_multiple_streams.py
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from sleekxmpp.test import *
|
||||||
|
|
||||||
|
|
||||||
|
class TestMultipleStreams(SleekTest):
|
||||||
|
"""
|
||||||
|
Test that we can test a live stanza stream.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.client1 = SleekTest()
|
||||||
|
self.client2 = SleekTest()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.client1.stream_close()
|
||||||
|
self.client2.stream_close()
|
||||||
|
|
||||||
|
def testMultipleStreams(self):
|
||||||
|
"""Test that we can interact with multiple live ClientXMPP instance."""
|
||||||
|
|
||||||
|
client1 = self.client1
|
||||||
|
client2 = self.client2
|
||||||
|
|
||||||
|
client1.stream_start(mode='client',
|
||||||
|
socket='live',
|
||||||
|
skip=True,
|
||||||
|
jid='user@localhost/test1',
|
||||||
|
password='user')
|
||||||
|
client2.stream_start(mode='client',
|
||||||
|
socket='live',
|
||||||
|
skip=True,
|
||||||
|
jid='user@localhost/test2',
|
||||||
|
password='user')
|
||||||
|
|
||||||
|
client1.xmpp.send_message(mto='user@localhost/test2',
|
||||||
|
mbody='test')
|
||||||
|
|
||||||
|
client1.send('message@body=test', method='stanzapath')
|
||||||
|
client2.recv('message@body=test', method='stanzapath')
|
||||||
|
|
||||||
|
|
||||||
|
suite = unittest.TestLoader().loadTestsFromTestCase(TestMultipleStreams)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
logging.basicConfig(level=logging.DEBUG,
|
||||||
|
format='%(levelname)-8s %(message)s')
|
||||||
|
|
||||||
|
tests = unittest.TestSuite([suite])
|
||||||
|
result = unittest.TextTestRunner(verbosity=2).run(tests)
|
||||||
|
test_ns = 'http://andyet.net/protocol/tests'
|
||||||
|
print("<tests xmlns='%s' %s %s %s %s />" % (
|
||||||
|
test_ns,
|
||||||
|
'ran="%s"' % result.testsRun,
|
||||||
|
'errors="%s"' % len(result.errors),
|
||||||
|
'fails="%s"' % len(result.failures),
|
||||||
|
'success="%s"' % result.wasSuccessful()))
|
|
@ -1,7 +1,6 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from sleekxmpp.test import *
|
from sleekxmpp.test import *
|
||||||
import sleekxmpp.plugins.xep_0033 as xep_0033
|
|
||||||
|
|
||||||
|
|
||||||
class TestLiveStream(SleekTest):
|
class TestLiveStream(SleekTest):
|
||||||
|
|
Loading…
Reference in a new issue