changeset 2589:282d1314d574

plugin XEP-0329: new methods/signals to handle shares: 2 new methods: - FISLocalSharesGet retrieve paths shared locally - FISUnsharePath stop sharing a file or directory 2 new signals: - FISSharedPathNew triggered when a new path is shared - FISSharedPathRemoved triggered when a path is not shared anymore
author Goffi <goffi@goffi.org>
date Tue, 22 May 2018 10:06:07 +0200
parents 4011e4ee3151
children bd9d92bc0d6c
files sat/plugins/plugin_xep_0234.py sat/plugins/plugin_xep_0329.py
diffstat 2 files changed, 73 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/sat/plugins/plugin_xep_0234.py	Tue May 22 10:01:00 2018 +0200
+++ b/sat/plugins/plugin_xep_0234.py	Tue May 22 10:06:07 2018 +0200
@@ -277,7 +277,7 @@
         """Request a file using jingle file transfer
 
         @param peer_jid(jid.JID): destinee jid
-        @param filepath(str): absolute path of the file
+        @param filepath(str): absolute path where the file will be downloaded
         @param name(unicode, None): name of the file
         @param file_hash(unicode, None): hash of the file
         @return (D(unicode)): progress id
--- a/sat/plugins/plugin_xep_0329.py	Tue May 22 10:01:00 2018 +0200
+++ b/sat/plugins/plugin_xep_0329.py	Tue May 22 10:06:07 2018 +0200
@@ -97,13 +97,16 @@
         return self.children.__contains__(item)
 
     def __iter__(self):
-        return self.children.__iter__
+        return self.children.__iter__()
 
     def iteritems(self):
         return self.children.iteritems()
 
+    def itervalues(self):
+        return self.children.itervalues()
+
     def getOrCreate(self, name, type_=TYPE_VIRTUAL, access=None):
-        """get a node or create a virtual one and return it"""
+        """get a node or create a virtual node and return it"""
         if access is None:
             access = {C.ACCESS_PERM_READ: {KEY_TYPE: C.ACCESS_TYPE_PUBLIC}}
         try:
@@ -118,6 +121,15 @@
         node.parent = self
         self.children[node.name] = node
 
+    def removeFromParent(self):
+        try:
+            del self.parent.children[self.name]
+        except TypeError:
+            raise exceptions.InternalError(u'trying to remove a node from inexisting parent')
+        except KeyError:
+            raise exceptions.InternalError(u"node not found in parent's children")
+        self.parent = None
+
     def _checkNodePermission(self, client, node, perms, peer_jid):
         """Check access to this node for peer_jid
 
@@ -192,6 +204,40 @@
 
         return node, u'/'.join(path_elts)
 
+    def findByLocalPath(self, path):
+        """retrieve nodes linking to local path
+
+        @return (list[ShareNode]): found nodes associated to path
+        @raise exceptions.NotFound: no node has been found with this path
+        """
+        shared_paths = self.getSharedPaths()
+        try:
+            return shared_paths[path]
+        except KeyError:
+            raise exceptions.NotFound
+
+    def _getSharedPaths(self, node, paths):
+        if node.type == TYPE_VIRTUAL:
+            for node in node.itervalues():
+                self._getSharedPaths(node, paths)
+        elif node.type == TYPE_PATH:
+            paths.setdefault(node.path, []).append(node)
+        else:
+            raise exceptions.InternalError(u'unknown node type: {type}'.format(
+                type = node.type))
+
+    def getSharedPaths(self):
+        """retrieve nodes by shared path
+
+        this method will retrieve recursively shared path in children of this node
+        @return (dict): map from shared path to list of nodes
+        """
+        if self.type == TYPE_PATH:
+            raise exceptions.InternalError("getSharedPaths must be used on a virtual node")
+        paths = {}
+        self._getSharedPaths(self, paths)
+        return paths
+
 
 class XEP_0329(object):
 
@@ -202,7 +248,11 @@
         self._h = host.plugins['XEP-0300']
         self._jf = host.plugins['XEP-0234']
         host.bridge.addMethod("FISList", ".plugin", in_sign='ssa{ss}s', out_sign='aa{ss}', method=self._listFiles, async=True)
+        host.bridge.addMethod("FISLocalSharesGet", ".plugin", in_sign='s', out_sign='as', method=self._localSharesGet)
         host.bridge.addMethod("FISSharePath", ".plugin", in_sign='ssss', out_sign='s', method=self._sharePath)
+        host.bridge.addMethod("FISUnsharePath", ".plugin", in_sign='ss', out_sign='', method=self._unsharePath)
+        host.bridge.addSignal("FISSharedPathNew", ".plugin", signature='sss')
+        host.bridge.addSignal("FISSharedPathRemoved", ".plugin", signature='ss')
         host.trigger.add("XEP-0234_fileSendingRequest", self._fileSendingRequestTrigger)
         host.registerNamespace('fis', NS_FIS)
 
@@ -504,6 +554,13 @@
         d.addCallback(self._parseResult)
         return d
 
+    def _localSharesGet(self, profile):
+        client = self.host.getClient(profile)
+        return self.localSharesGet(client)
+
+    def localSharesGet(self, client):
+        return client._XEP_0329_root_node.getSharedPaths().keys()
+
     def _sharePath(self, name, path, access, profile):
         client = self.host.getClient(profile)
         access= json.loads(access)
@@ -516,6 +573,8 @@
             raise ValueError(_(u"This path doesn't exist!"))
         if not path or not path.strip(u' /'):
             raise ValueError(_(u"A path need to be specified"))
+        if not isinstance(access, dict):
+            raise ValueError(_(u'access must be a dict'))
 
         node = client._XEP_0329_root_node
         node_type = TYPE_PATH
@@ -528,9 +587,6 @@
             if not name:
                 raise exceptions.InternalError(_(u"Can't find a proper name"))
 
-        if not isinstance(access, dict):
-            raise ValueError(_(u'access must be a dict'))
-
         if name in node or name == SINGLE_FILES_DIR:
             idx = 1
             new_name = name + '_' + unicode(idx)
@@ -542,8 +598,19 @@
                 new_name=new_name, profile=client.profile)))
 
         ShareNode(name=name, parent=node, type_=node_type, access=access, path=path)
+        self.host.bridge.FISSharedPathNew(path, name, client.profile)
         return name
 
+    def _unsharePath(self, path, profile):
+        client = self.host.getClient(profile)
+        return self.unsharePath(client, path)
+
+    def unsharePath(self, client, path):
+        nodes = client._XEP_0329_root_node.findByLocalPath(path)
+        for node in nodes:
+            node.removeFromParent()
+        self.host.bridge.FISSharedPathRemoved(path, client.profile)
+
 
 class XEP_0329_handler(xmlstream.XMPPHandler):
     implements(iwokkel.IDisco)