comparison wokkel/rsm.py @ 23:777b4e63fc8a

plugin XEP-0060, tmp(wokkel.rsm): small refactoring: - don't use getRSMResponse anymore: rsm.PubSubClient use a different signature which return items and RSMResponse, this is better than the previous method as if the requested don't call getRSMResponse, there is no memory leak anymore. - use RSMResponse directly instead of using ext_data, as other extension (like MAM) will be probably be managed with an other workflow - don't do a useless deep copy of pubsub.PubSubRequest._parameters on each instance anymore - RSMResponse.parse do now manage parsing of <set/> element directly
author Goffi <goffi@goffi.org>
date Tue, 05 Jan 2016 23:20:22 +0100
parents 54f834e40341
children 4816f7d55367
comparison
equal deleted inserted replaced
22:5246a9186b91 23:777b4e63fc8a
84 84
85 @classmethod 85 @classmethod
86 def fromElement(cls, element): 86 def fromElement(cls, element):
87 """Parse the given request element. 87 """Parse the given request element.
88 88
89 @param element: request containing a set element. 89 @param element: request containing a set element, or set element itself.
90 @type element: L{domish.Element} 90 @type element: L{domish.Element}
91 91
92 @return: RSMRequest instance. 92 @return: RSMRequest instance.
93 @rtype: L{RSMRequest} 93 @rtype: L{RSMRequest}
94 """ 94 """
95 try: 95
96 set_elt = element.elements(NS_RSM, 'set').next() 96 if element.name == 'set' and element.uri == NS_RSM:
97 except StopIteration: 97 set_elt = element
98 raise RSMNotFoundError() 98 else:
99 try:
100 set_elt = element.elements(NS_RSM, 'set').next()
101 except StopIteration:
102 raise RSMNotFoundError()
99 103
100 try: 104 try:
101 before_elt = set_elt.elements(NS_RSM, 'before').next() 105 before_elt = set_elt.elements(NS_RSM, 'before').next()
102 except StopIteration: 106 except StopIteration:
103 before = None 107 before = None
318 @ivar rsm: RSM request instance. 322 @ivar rsm: RSM request instance.
319 @type rsm: L{RSMRequest} 323 @type rsm: L{RSMRequest}
320 """ 324 """
321 325
322 rsm = None 326 rsm = None
323 327 _parameters = copy.deepcopy(pubsub.PubSubRequest._parameters)
324 def __init__(self, verb=None): 328 _parameters['items'].append('rsm')
325 super(PubSubRequest, self).__init__(verb)
326 self._parameters = copy.deepcopy(pubsub.PubSubRequest._parameters)
327 self._parameters['items'].append('rsm')
328 329
329 def _parse_rsm(self, verbElement): 330 def _parse_rsm(self, verbElement):
330 try: 331 try:
331 self.rsm = RSMRequest.fromElement(verbElement.parent) 332 self.rsm = RSMRequest.fromElement(verbElement.parent)
332 except RSMNotFoundError: 333 except RSMNotFoundError:
338 339
339 340
340 class PubSubClient(pubsub.PubSubClient): 341 class PubSubClient(pubsub.PubSubClient):
341 """PubSubClient extension to handle RSM.""" 342 """PubSubClient extension to handle RSM."""
342 343
343 _rsm_responses = {} 344 _request_class = PubSubRequest
344 345
345 def items(self, service, nodeIdentifier, maxItems=None, itemIdentifiers=None, 346 def items(self, service, nodeIdentifier, maxItems=None, itemIdentifiers=None,
346 subscriptionIdentifier=None, sender=None, ext_data=None): 347 subscriptionIdentifier=None, sender=None, rsm_request=None):
347 """ 348 """
348 Retrieve previously published items from a publish subscribe node. 349 Retrieve previously published items from a publish subscribe node.
349 350
350 @param service: The publish subscribe service that keeps the node. 351 @param service: The publish subscribe service that keeps the node.
351 @type service: L{JID<twisted.words.protocols.jabber.jid.JID>} 352 @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}
365 @type subscriptionIdentifier: C{unicode} 366 @type subscriptionIdentifier: C{unicode}
366 367
367 @param ext_data: extension data. 368 @param ext_data: extension data.
368 @type ext_data: L{dict} 369 @type ext_data: L{dict}
369 370
370 @return: a Deferred that fires a C{list} of L{domish.Element}. 371 @return: a Deferred that fires a C{list} of C{tuple} of L{domish.Element}, L{RSMResponse}.
371 @rtype: L{defer.Deferred} 372 @rtype: L{defer.Deferred}
372 """ 373 """
373 request = PubSubRequest('items') # that's a rsm.PubSubRequest instance 374 # XXX: we have to copy initial method instead of calling it,
375 # as original cb remove all non item elements
376 request = self._request_class('items')
374 request.recipient = service 377 request.recipient = service
375 request.nodeIdentifier = nodeIdentifier 378 request.nodeIdentifier = nodeIdentifier
376 if maxItems is not None: 379 if maxItems:
377 request.maxItems = str(int(maxItems)) 380 request.maxItems = str(int(maxItems))
378 request.subscriptionIdentifier = subscriptionIdentifier 381 request.subscriptionIdentifier = subscriptionIdentifier
379 request.sender = sender 382 request.sender = sender
380 request.itemIdentifiers = itemIdentifiers 383 request.itemIdentifiers = itemIdentifiers
381 if ext_data and 'rsm' in ext_data: 384 request.rsm = rsm_request
382 request.rsm = ext_data['rsm']
383 385
384 def cb(iq): 386 def cb(iq):
385 items = [] 387 items = []
386 if iq.pubsub.items: 388 pubsub_elt = iq.pubsub
387 for element in iq.pubsub.items.elements(pubsub.NS_PUBSUB, 'item'): 389 for element in pubsub_elt.items.elements(pubsub.NS_PUBSUB, 'item'):
388 items.append(element) 390 items.append(element)
389 391
390 if request.rsm: 392 try:
391 try: 393 rsm_response = RSMResponse.parse(pubsub_elt)
392 response = RSMResponse.fromElement(iq.pubsub) 394 except RSMNotFoundError:
393 if response is not None: 395 rsm_response = None
394 self._rsm_responses[ext_data['id']] = response 396 return (items, rsm_response)
395 except RSMNotFoundError: # target pubsub server doesn't support RSM
396 pass
397 return items
398 397
399 d = request.send(self.xmlstream) 398 d = request.send(self.xmlstream)
400 d.addCallback(cb) 399 d.addCallback(cb)
401 return d 400 return d
402
403 def getRSMResponse(self, id_):
404 """Post-retrieve the RSM response data after items retrieval is done.
405
406 @param id_: extension data ID
407 @type id_: C{unicode}
408
409 @return: dict representation of the RSM response.
410 @rtype: C{dict} of C{unicode}
411 """
412 # This method exists to not modify the return value of self.items.
413 if id_ not in self._rsm_responses:
414 return {}
415 result = self._rsm_responses[id_].toDict()
416 del self._rsm_responses[id_]
417 return result
418 401
419 402
420 class PubSubService(pubsub.PubSubService): 403 class PubSubService(pubsub.PubSubService):
421 """PubSubService extension to handle RSM.""" 404 """PubSubService extension to handle RSM."""
422 405