comparison src/plugins/plugin_xep_0277.py @ 1454:4e2fab4de195

plugin XEP-0277: added mBGetFromManyWithComments to have items + comments in one method call
author Goffi <goffi@goffi.org>
date Sat, 15 Aug 2015 22:24:38 +0200
parents d5e72362ee91
children 4c4f88d7b156
comparison
equal deleted inserted replaced
1453:d5e72362ee91 1454:4e2fab4de195
24 from twisted.words.protocols.jabber import jid 24 from twisted.words.protocols.jabber import jid
25 from twisted.internet import defer 25 from twisted.internet import defer
26 from twisted.python import failure 26 from twisted.python import failure
27 from sat.core import exceptions 27 from sat.core import exceptions
28 from sat.tools.xml_tools import ElementParser 28 from sat.tools.xml_tools import ElementParser
29 from sat.tools import sat_defer
29 30
30 from wokkel import pubsub 31 from wokkel import pubsub
31 from wokkel import rsm 32 from wokkel import rsm
32 from feed import atom, date 33 from feed import atom, date
33 import uuid 34 import uuid
61 62
62 def __init__(self, host): 63 def __init__(self, host):
63 log.info(_("Microblogging plugin initialization")) 64 log.info(_("Microblogging plugin initialization"))
64 self.host = host 65 self.host = host
65 self._p = self.host.plugins["XEP-0060"] # this facilitate the access to pubsub plugin 66 self._p = self.host.plugins["XEP-0060"] # this facilitate the access to pubsub plugin
67 self.rt_sessions = sat_defer.RTDeferredSessions()
66 self.host.plugins["XEP-0163"].addPEPEvent("MICROBLOG", NS_MICROBLOG, self.microblogCB, self.sendMicroblog, notify=False) 68 self.host.plugins["XEP-0163"].addPEPEvent("MICROBLOG", NS_MICROBLOG, self.microblogCB, self.sendMicroblog, notify=False)
67 host.bridge.addMethod("getLastMicroblogs", ".plugin", 69 host.bridge.addMethod("getLastMicroblogs", ".plugin",
68 in_sign='sis', out_sign='(aa{ss}a{ss})', 70 in_sign='sis', out_sign='(aa{ss}a{ss})',
69 method=self._getLastMicroblogs, 71 method=self._getLastMicroblogs,
70 async=True, 72 async=True,
80 method=self._mBSubscribeToMany) 82 method=self._mBSubscribeToMany)
81 host.bridge.addMethod("mBGetFromManyRTResult", ".plugin", in_sign='ss', out_sign='(ua(sssaa{ss}a{ss}))', 83 host.bridge.addMethod("mBGetFromManyRTResult", ".plugin", in_sign='ss', out_sign='(ua(sssaa{ss}a{ss}))',
82 method=self._mBGetFromManyRTResult, async=True) 84 method=self._mBGetFromManyRTResult, async=True)
83 host.bridge.addMethod("mBGetFromMany", ".plugin", in_sign='sasia{ss}s', out_sign='s', 85 host.bridge.addMethod("mBGetFromMany", ".plugin", in_sign='sasia{ss}s', out_sign='s',
84 method=self._mBGetFromMany) 86 method=self._mBGetFromMany)
87 host.bridge.addMethod("mBGetFromManyWithCommentsRTResult", ".plugin", in_sign='ss', out_sign='(ua(sssa(a{ss}a(sssaa{ss}a{ss}))a{ss}))',
88 method=self._mBGetFromManyWithCommentsRTResult, async=True)
89 host.bridge.addMethod("mBGetFromManyWithComments", ".plugin", in_sign='sasiia{ss}a{ss}s', out_sign='s', method=self._mBGetFromManyWithComments)
85 90
86 ## plugin management methods ## 91 ## plugin management methods ##
87 92
88 def microblogCB(self, itemsEvent, profile): 93 def microblogCB(self, itemsEvent, profile):
89 """Callback to "MICROBLOG" PEP event.""" 94 """Callback to "MICROBLOG" PEP event."""
563 - the microblogs data 568 - the microblogs data
564 - RSM response data 569 - RSM response data
565 """ 570 """
566 client, node_data = self._getClientAndNodeData(publishers_type, publishers, profile_key) 571 client, node_data = self._getClientAndNodeData(publishers_type, publishers, profile_key)
567 return self._p.getFromMany(node_data, max_item, rsm_data, profile_key=profile_key) 572 return self._p.getFromMany(node_data, max_item, rsm_data, profile_key=profile_key)
573
574 # comments #
575
576 def _mBGetFromManyWithCommentsRTResult(self, session_id, profile_key=C.PROF_KEY_DEFAULT):
577 """Get real-time results for [mBGetFromManyWithComments] session
578
579 @param session_id: id of the real-time deferred session
580 @param return (tuple): (remaining, results) where:
581 - remaining is the number of still expected results
582 - results is a list of tuple with
583 - service (unicode): pubsub service
584 - node (unicode): pubsub node
585 - success (bool): True if the getItems was successful
586 - failure (unicode): empty string in case of success, error message else
587 - items(list): list of items with:
588 - item(dict): item microblog data
589 - comments_list(list): list of comments with
590 - service (unicode): pubsub service where the comments node is
591 - node (unicode): comments node
592 - failure (unicode): empty in case of success, else error message
593 - comments(list[dict]): list of microblog data
594 - comments_metadata(dict): metadata of the comment node
595 - metadata(dict): original node metadata
596 @param profile_key: %(doc_profile_key)s
597 """
598 profile = self.host.getClient(profile_key).profile
599 d = self.rt_sessions.getResults(session_id, profile=profile)
600 d.addCallback(lambda ret: (ret[0],
601 [(service.full(), node, failure, items, metadata)
602 for (service, node), (success, (failure, (items, metadata))) in ret[1].iteritems()]))
603 return d
604
605 def _mBGetFromManyWithComments(self, publishers_type, publishers, max_item=10, max_comments=C.NO_LIMIT, rsm_dict=None, rsm_comments_dict=None, profile_key=C.PROF_KEY_NONE):
606 """
607 @param max_item(int): maximum number of item to get, C.NO_LIMIT for no limit
608 @param max_comments(int): maximum number of comments to get, C.NO_LIMIT for no limit
609 """
610 max_item = None if max_item == C.NO_LIMIT else max_item
611 max_comments = None if max_comments == C.NO_LIMIT else max_comments
612 publishers_type, publishers = self._checkPublishers(publishers_type, publishers)
613 return self.mBGetFromManyWithComments(publishers_type, publishers, max_item, max_comments,
614 rsm.RSMRequest(**rsm_dict) if rsm_dict else None,
615 rsm.RSMRequest(**rsm_comments_dict) if rsm_comments_dict else None,
616 profile_key)
617
618 def mBGetFromManyWithComments(self, publishers_type, publishers, max_item=None, max_comments=None, rsm_request=None, rsm_comments=None, profile_key=C.PROF_KEY_NONE):
619 """Helper method to get the microblogs and their comments in one shot
620
621 @param publishers_type (str): type of the list of publishers (one of "GROUP" or "JID" or "ALL")
622 @param publishers (list): list of publishers, according to publishers_type (list of groups or list of jids)
623 @param max_items (int): optional limit on the number of retrieved items.
624 @param max_comments (int): maximum number of comments to retrieve
625 @param rsm_request (rsm.RSMRequest): RSM request for initial items only
626 @param rsm_comments (rsm.RSMRequest): RSM request for comments only
627 @param profile_key: profile key
628 @return: a deferred dict with:
629 - key: publisher (unicode)
630 - value: couple (list[dict], dict) with:
631 - the microblogs data
632 - RSM response data
633 """
634 # XXX: this method seems complicated because it do a couple of treatments
635 # to serialise and associate the data, but it make life in frontends side
636 # a lot easier
637
638 def getComments(items_data):
639 """Retrieve comments and add them to the items_data
640
641 @param items_data: serialised items data
642 @return (defer.Deferred): list of items where each item is associated
643 with a list of comments data (service, node, list of items, metadata)
644 """
645 items, metadata = items_data
646 items_dlist = [] # deferred list for items
647 for item in items:
648 dlist = [] # deferred list for comments
649 for key, value in item.iteritems():
650 # we look for comments
651 if key.startswith('comments') and key.endswith('_service'):
652 prefix = key[:key.find('_')]
653 service_s = value
654 node = item["{}{}".format(prefix, "_node")]
655 # time to get the comments
656 d = self._p.getItems(jid.JID(service_s), node, max_comments, rsm_request=rsm_comments, profile_key=profile_key)
657 # then serialise
658 d.addCallback(lambda items_data: self._p.serItemsDataD(items_data, self.item2mbdata))
659 # with failure handling
660 d.addCallback(lambda serialised_items_data: ('',) + serialised_items_data)
661 d.addErrback(lambda failure: (unicode(failure.value), [], {}))
662 # and associate with service/node (needed if there are several comments nodes)
663 d.addCallback(lambda serialised: (service_s, node) + serialised)
664 dlist.append(d)
665 # we get the comments
666 comments_d = defer.gatherResults(dlist)
667 # and add them to the item data
668 comments_d.addCallback(lambda comments_data: (item, comments_data))
669 items_dlist.append(comments_d)
670 # we gather the items + comments in a list
671 items_d = defer.gatherResults(items_dlist)
672 # and add the metadata
673 items_d.addCallback(lambda items: (items, metadata))
674 return items_d
675
676 client, node_data = self._getClientAndNodeData(publishers_type, publishers, profile_key)
677 deferreds = {}
678 for service, node in node_data:
679 d = deferreds[(service, node)] = self._p.getItems(service, node, max_item, rsm_request=rsm_request, profile_key=profile_key)
680 d.addCallback(lambda items_data: self._p.serItemsDataD(items_data, self.item2mbdata))
681 d.addCallback(getComments)
682 d.addCallback(lambda items_comments_data: ('', items_comments_data))
683 d.addErrback(lambda failure: (unicode(failure.value), ([],{})))
684
685 return self.rt_sessions.newSession(deferreds, client.profile)