comparison src/plugins/plugin_xep_0060.py @ 1267:ea692d51a0ee

plugins XEP-0059, XEP-0060: leave internal wokkel extensions to sat.tmp.wokkel
author souliane <souliane@mailoo.org>
date Mon, 15 Dec 2014 14:03:13 +0100
parents 93bce9e4c9c8
children bb30bf3ae932
comparison
equal deleted inserted replaced
1266:9141bde7ff31 1267:ea692d51a0ee
21 from sat.core.constants import Const as C 21 from sat.core.constants import Const as C
22 from sat.core.log import getLogger 22 from sat.core.log import getLogger
23 log = getLogger(__name__) 23 log = getLogger(__name__)
24 from sat.memory.memory import Sessions 24 from sat.memory.memory import Sessions
25 25
26 from wokkel.compat import IQ 26 from wokkel import disco, pubsub, rsm
27 from wokkel import disco, pubsub
28 from zope.interface import implements 27 from zope.interface import implements
29 from twisted.internet import defer 28 from twisted.internet import defer
30 29
31 30
32 PLUGIN_INFO = { 31 PLUGIN_INFO = {
230 def subscriptions(self, service, nodeIdentifier='', profile_key=C.PROF_KEY_NONE): 229 def subscriptions(self, service, nodeIdentifier='', profile_key=C.PROF_KEY_NONE):
231 profile, client = self.__getClientNProfile(profile_key, 'retrieve subscriptions') 230 profile, client = self.__getClientNProfile(profile_key, 'retrieve subscriptions')
232 return client.subscriptions(service, nodeIdentifier) 231 return client.subscriptions(service, nodeIdentifier)
233 232
234 233
235 class SatPubSubClient(pubsub.PubSubClient): 234 class SatPubSubClient(rsm.PubSubClient):
236 implements(disco.IDisco) 235 implements(disco.IDisco)
237 236
238 def __init__(self, host, parent_plugin): 237 def __init__(self, host, parent_plugin):
239 self.host = host 238 self.host = host
240 self.parent_plugin = parent_plugin 239 self.parent_plugin = parent_plugin
241 pubsub.PubSubClient.__init__(self) 240 rsm.PubSubClient.__init__(self)
242 241
243 def connectionInitialized(self): 242 def connectionInitialized(self):
244 pubsub.PubSubClient.connectionInitialized(self) 243 rsm.PubSubClient.connectionInitialized(self)
245
246 # FIXME: we have to temporary override this method here just
247 # to set the attributes itemIdentifiers which is not used
248 # in pubsub.PubSubClient.items + use the XEP-0059
249 def items(self, service, nodeIdentifier, maxItems=None, itemIdentifiers=None,
250 subscriptionIdentifier=None, sender=None):
251 """
252 Retrieve previously published items from a publish subscribe node.
253
254 @param service: The publish subscribe service that keeps the node.
255 @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}
256
257 @param nodeIdentifier: The identifier of the node.
258 @type nodeIdentifier: C{unicode}
259
260 @param maxItems: Optional limit on the number of retrieved items.
261 @type maxItems: C{int}
262
263 @param itemIdentifiers: Identifiers of the items to be retrieved.
264 @type itemIdentifiers: C{set}
265
266 @param subscriptionIdentifier: Optional subscription identifier. In
267 case the node has been subscribed to multiple times, this narrows
268 the results to the specific subscription.
269 @type subscriptionIdentifier: C{unicode}
270 """
271 # TODO: add method attributes for RSM: before, after, index
272 request = PubSubRequest('items', self.host, {'limit': maxItems} if maxItems else {})
273 request.recipient = service
274 request.nodeIdentifier = nodeIdentifier
275 if maxItems:
276 request.maxItems = str(int(maxItems))
277 request.subscriptionIdentifier = subscriptionIdentifier
278 request.sender = sender
279 request.itemIdentifiers = itemIdentifiers # XXX: this line has been added
280
281 def cb(iq):
282 items = []
283 for element in iq.pubsub.items.elements():
284 if element.uri == pubsub.NS_PUBSUB and element.name == 'item':
285 items.append(element)
286 # TODO: return (items, self.host.plugins['XEP-0059'].extractMetadata(iq)) ??
287 return items
288
289 d = request.send(self.xmlstream)
290 d.addCallback(cb)
291 return d
292
293 # FIXME: this should be done in wokkel
294 def retractItems(self, service, nodeIdentifier, itemIdentifiers, sender=None):
295 """
296 Retract items from a publish subscribe node.
297
298 @param service: The publish subscribe service to delete the node from.
299 @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}
300 @param nodeIdentifier: The identifier of the node.
301 @type nodeIdentifier: C{unicode}
302 @param itemIdentifiers: Identifiers of the items to be retracted.
303 @type itemIdentifiers: C{set}
304 """
305 request = PubSubRequest('retract')
306 request.recipient = service
307 request.nodeIdentifier = nodeIdentifier
308 request.itemIdentifiers = itemIdentifiers
309 request.sender = sender
310 return request.send(self.xmlstream)
311 244
312 def itemsReceived(self, event): 245 def itemsReceived(self, event):
313 if not self.host.trigger.point("PubSubItemsReceived", event, self.parent.profile): 246 if not self.host.trigger.point("PubSubItemsReceived", event, self.parent.profile):
314 return 247 return
315 for node in self.parent_plugin.managedNodes: 248 for node in self.parent_plugin.managedNodes:
320 #TODO: manage delete event 253 #TODO: manage delete event
321 log.debug(_("Publish node deleted")) 254 log.debug(_("Publish node deleted"))
322 255
323 # def purgeReceived(self, event): 256 # def purgeReceived(self, event):
324 257
325 @defer.inlineCallbacks
326 def subscriptions(self, service, nodeIdentifier, sender=None): 258 def subscriptions(self, service, nodeIdentifier, sender=None):
327 """Return the list of subscriptions to the given service and node. 259 """Return the list of subscriptions to the given service and node.
328 260
329 @param service: The publish subscribe service to retrieve the subscriptions from. 261 @param service: The publish subscribe service to retrieve the subscriptions from.
330 @type service: L{JID<twisted.words.protocols.jabber.jid.JID>} 262 @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}
331 @param nodeIdentifier: The identifier of the node (leave empty to retrieve all subscriptions). 263 @param nodeIdentifier: The identifier of the node (leave empty to retrieve all subscriptions).
332 @type nodeIdentifier: C{unicode} 264 @type nodeIdentifier: C{unicode}
333 """ 265 """
334 request = PubSubRequest('subscriptions') 266 request = pubsub.PubSubRequest('subscriptions')
335 request.recipient = service 267 request.recipient = service
336 request.nodeIdentifier = nodeIdentifier 268 request.nodeIdentifier = nodeIdentifier
337 request.sender = sender 269 request.sender = sender
338 iq = yield request.send(self.xmlstream) 270 d = request.send(self.xmlstream)
339 defer.returnValue([sub for sub in iq.pubsub.subscriptions.elements() if 271
340 (sub.uri == pubsub.NS_PUBSUB and sub.name == 'subscription')]) 272 def cb(iq):
273 return [sub for sub in iq.pubsub.subscriptions.elements() if
274 (sub.uri == pubsub.NS_PUBSUB and sub.name == 'subscription')]
275
276 return d.addCallback(cb)
341 277
342 def getDiscoInfo(self, requestor, service, nodeIdentifier=''): 278 def getDiscoInfo(self, requestor, service, nodeIdentifier=''):
343 disco_info = [] 279 disco_info = []
344 self.host.trigger.point("PubSub Disco Info", disco_info, self.parent.profile) 280 self.host.trigger.point("PubSub Disco Info", disco_info, self.parent.profile)
345 return disco_info 281 return disco_info
346 282
347 def getDiscoItems(self, requestor, service, nodeIdentifier=''): 283 def getDiscoItems(self, requestor, service, nodeIdentifier=''):
348 return [] 284 return []
349
350
351 class PubSubRequest(pubsub.PubSubRequest):
352
353 def __init__(self, verb=None, host=None, page_attrs=None):
354 """
355 @param verb (str): the type of pubsub request
356 @param host (SAT): the SAT instance
357 @param page_attrs (dict): options for RSM paging:
358 - limit (int): the maximum number of items in the page
359 - index (int): the starting index of the requested page
360 - after (str, int): the element immediately preceding the page
361 - before (str, int): the element immediately following the page
362 """
363 self.verb = verb
364 self.host = host
365 self.page_attrs = page_attrs
366
367 # FIXME: the redefinition of this wokkel method is the easiest way I found
368 # to handle RSM. We should find a proper solution, maybe just add in wokkel an
369 # empty method postProcessMessage, call it before sending and overwrite it here
370 # instead of overwriting the whole send method.
371 def send(self, xs):
372 """
373 Send this request to its recipient.
374
375 This renders all of the relevant parameters for this specific
376 requests into an L{IQ}, and invoke its C{send} method.
377 This returns a deferred that fires upon reception of a response. See
378 L{IQ} for details.
379
380 @param xs: The XML stream to send the request on.
381 @type xs: L{twisted.words.protocols.jabber.xmlstream.XmlStream}
382 @rtype: L{defer.Deferred}.
383 """
384
385 try:
386 (self.stanzaType,
387 childURI,
388 childName) = self._verbRequestMap[self.verb]
389 except KeyError:
390 raise NotImplementedError()
391
392 iq = IQ(xs, self.stanzaType)
393 iq.addElement((childURI, 'pubsub'))
394 verbElement = iq.pubsub.addElement(childName)
395
396 if self.sender:
397 iq['from'] = self.sender.full()
398 if self.recipient:
399 iq['to'] = self.recipient.full()
400
401 for parameter in self._parameters[self.verb]:
402 getattr(self, '_render_%s' % parameter)(verbElement)
403
404 # This lines have been added for RSM
405 if self.host and 'XEP-0059' in self.host.plugins and self.page_attrs:
406 self.page_attrs['stanza'] = iq
407 self.host.plugins['XEP-0059'].requestPage(**self.page_attrs)
408
409 return iq.send()