Prevent roster_update from firing twice after retrieving the roster.

This commit is contained in:
Lance Stout 2012-04-07 17:19:39 -04:00
parent 9f855b9679
commit 7734aee7ad
2 changed files with 26 additions and 27 deletions

View file

@ -20,7 +20,7 @@ from sleekxmpp.stanza import StreamFeatures
from sleekxmpp.basexmpp import BaseXMPP from sleekxmpp.basexmpp import BaseXMPP
from sleekxmpp.exceptions import XMPPError from sleekxmpp.exceptions import XMPPError
from sleekxmpp.xmlstream import XMLStream from sleekxmpp.xmlstream import XMLStream
from sleekxmpp.xmlstream.matcher import MatchXPath from sleekxmpp.xmlstream.matcher import StanzaPath, MatchXPath
from sleekxmpp.xmlstream.handler import Callback from sleekxmpp.xmlstream.handler import Callback
# Flag indicating if DNS SRV records are available for use. # Flag indicating if DNS SRV records are available for use.
@ -103,9 +103,7 @@ class ClientXMPP(BaseXMPP):
self._handle_stream_features)) self._handle_stream_features))
self.register_handler( self.register_handler(
Callback('Roster Update', Callback('Roster Update',
MatchXPath('{%s}iq/{%s}query' % ( StanzaPath('iq@type=set/roster'),
self.default_ns,
'jabber:iq:roster')),
self._handle_roster)) self._handle_roster))
# Setup default stream features # Setup default stream features
@ -230,7 +228,8 @@ class ClientXMPP(BaseXMPP):
response = iq.send(block, timeout, callback) response = iq.send(block, timeout, callback)
if block: if block:
self._handle_roster(response, request=True) self.event('roster_received', response)
self._handle_roster(response)
return response return response
def _handle_connected(self, event=None): def _handle_connected(self, event=None):
@ -254,32 +253,28 @@ class ClientXMPP(BaseXMPP):
# restarting the XML stream. # restarting the XML stream.
return True return True
def _handle_roster(self, iq, request=False): def _handle_roster(self, iq):
"""Update the roster after receiving a roster stanza. """Update the roster after receiving a roster stanza.
:param iq: The roster stanza. :param iq: The roster stanza.
:param request: Indicates if this stanza is a response
to a request for the roster, and not an
empty acknowledgement from the server.
""" """
if iq['from'].bare and iq['from'].bare != self.boundjid.bare: if iq['type'] == 'set':
raise XMPPError(condition='service-unavailable') if iq['from'].bare and iq['from'].bare != self.boundjid.bare:
if iq['type'] == 'set' or (iq['type'] == 'result' and request): raise XMPPError(condition='service-unavailable')
roster = self.client_roster
if iq['roster']['ver']:
roster.version = iq['roster']['ver']
for jid in iq['roster']['items']:
item = iq['roster']['items'][jid]
roster[jid]['name'] = item['name']
roster[jid]['groups'] = item['groups']
roster[jid]['from'] = item['subscription'] in ['from', 'both']
roster[jid]['to'] = item['subscription'] in ['to', 'both']
roster[jid]['pending_out'] = (item['ask'] == 'subscribe')
roster[jid].save(remove=(item['subscription'] == 'remove')) roster = self.client_roster
if iq['roster']['ver']:
self.event('roster_received', iq) roster.version = iq['roster']['ver']
for jid in iq['roster']['items']:
item = iq['roster']['items'][jid]
roster[jid]['name'] = item['name']
roster[jid]['groups'] = item['groups']
roster[jid]['from'] = item['subscription'] in ['from', 'both']
roster[jid]['to'] = item['subscription'] in ['to', 'both']
roster[jid]['pending_out'] = (item['ask'] == 'subscribe')
roster[jid].save(remove=(item['subscription'] == 'remove'))
self.event("roster_update", iq) self.event("roster_update", iq)
if iq['type'] == 'set': if iq['type'] == 'set':
iq.reply() iq.reply()

View file

@ -24,7 +24,11 @@ class TestStreamRoster(SleekTest):
def roster_received(iq): def roster_received(iq):
events.append('roster_received') events.append('roster_received')
def roster_update(iq):
events.append('roster_update')
self.xmpp.add_event_handler('roster_received', roster_received) self.xmpp.add_event_handler('roster_received', roster_received)
self.xmpp.add_event_handler('roster_update', roster_update)
# Since get_roster blocks, we need to run it in a thread. # Since get_roster blocks, we need to run it in a thread.
t = threading.Thread(name='get_roster', target=self.xmpp.get_roster) t = threading.Thread(name='get_roster', target=self.xmpp.get_roster)
@ -62,8 +66,8 @@ class TestStreamRoster(SleekTest):
# Give the event queue time to process. # Give the event queue time to process.
time.sleep(.1) time.sleep(.1)
self.failUnless('roster_received' in events, self.failUnless(events == ['roster_received', 'roster_update'],
"Roster received event not triggered: %s" % events) "Wrong roster events fired: %s" % events)
def testRosterSet(self): def testRosterSet(self):
"""Test handling pushed roster updates.""" """Test handling pushed roster updates."""