changeset 1093:eda7a1c6532a

server: new getAffiliation method: getAffiliation allows to retrieve affiliation to a pubsub node for logged user. The method handle cache in user's session, avoiding requesting pubsub service when possible.
author Goffi <goffi@goffi.org>
date Fri, 01 Jun 2018 13:03:52 +0200
parents 63ed5f6bd4eb
children 8a270f32de81
files src/server/server.py src/server/session_iface.py
diffstat 2 files changed, 71 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/server/server.py	Fri Jun 01 12:58:20 2018 +0200
+++ b/src/server/server.py	Fri Jun 01 13:03:52 2018 +0200
@@ -1920,6 +1920,37 @@
         else:
             return (iface(session) for iface in args)
 
+    @defer.inlineCallbacks
+    def getAffiliation(self, request, service, node):
+        """retrieve pubsub node affiliation for current user
+
+        use cache first, and request pubsub service if not cache is found
+        @param request(server.Request): request linked to the session
+        @param service(jid.JID): pubsub service
+        @param node(unicode): pubsub node
+        @return (unicode): affiliation
+        """
+        sat_session = self.getSessionData(request, session_iface.ISATSession)
+        if sat_session.profile is None:
+            raise exceptions.InternalError(u'profile must be set to use this method')
+        affiliation = sat_session.getAffiliation(service, node)
+        if affiliation is not None:
+            defer.returnValue(affiliation)
+        else:
+            try:
+                affiliations = yield self.bridgeCall('psAffiliationsGet', service.full(), node, sat_session.profile)
+            except Exception as e:
+                log.warning("Can't retrieve affiliation for {service}/{node}: {reason}".format(
+                    service=service, node=node, reason=e))
+                affiliation = u""
+            else:
+                try:
+                    affiliation = affiliations[node]
+                except KeyError:
+                    affiliation = u""
+            sat_session.setAffiliation(service, node, affiliation)
+            defer.returnValue(affiliation)
+
     ## Websocket (dynamic pages) ##
 
     def getWebsocketURL(self, request):
--- a/src/server/session_iface.py	Fri Jun 01 12:58:20 2018 +0200
+++ b/src/server/session_iface.py	Fri Jun 01 13:03:52 2018 +0200
@@ -19,11 +19,13 @@
 from zope.interface import Interface, Attribute, implements
 from sat.tools.common import data_objects
 from libervia.server.constants import Const as C
+from collections import OrderedDict
 import os.path
 import shortuuid
 import time
 
 FLAGS_KEY = '_flags'
+MAX_CACHE_AFFILIATIONS = 100  # number of nodes to keep in cache
 
 class ISATSession(Interface):
     profile = Attribute("Sat profile")
@@ -45,6 +47,7 @@
         self.identities = data_objects.Identities()
         self.csrf_token = unicode(shortuuid.uuid())
         self.pages_data = {}  # used to keep data accross reloads (key is page instance)
+        self.affiliations = OrderedDict()  # cache for node affiliations
 
     @property
     def cache_dir(self):
@@ -125,6 +128,43 @@
         else:
             return False
 
+    def getAffiliation(self, service, node):
+        """retrieve affiliation for a pubsub node
+
+        @param service(jid.JID): pubsub service
+        @param node(unicode): pubsub node
+        @return (unicode, None): affiliation, or None if it is not in cache
+        """
+        if service.resource:
+            raise ValueError(u"Service must not have a resource")
+        if not node:
+            raise ValueError(u"node must be set")
+        try:
+            affiliation = self.affiliations.pop((service, node))
+        except KeyError:
+            return None
+        else:
+            # we replace at the top to get the most recently used on top
+            # so less recently used will be removed if cache is full
+            self.affiliations[(service, node)] = affiliation
+            return affiliation
+
+    def setAffiliation(self, service, node, affiliation):
+        """cache affiliation for a node
+
+        will empty cache when it become too big
+        @param service(jid.JID): pubsub service
+        @param node(unicode): pubsub node
+        @param affiliation(unicode): affiliation to this node
+        """
+        if service.resource:
+            raise ValueError(u"Service must not have a resource")
+        if not node:
+            raise ValueError(u"node must be set")
+        self.affiliations[(service, node)] = affiliation
+        while len(self.affiliations) > MAX_CACHE_AFFILIATIONS:
+            self.affiliations.popitem(last=False)
+
 
 class ISATGuestSession(Interface):
     id = Attribute("UUID of the guest")