# HG changeset patch # User Goffi # Date 1526976367 -7200 # Node ID 282d1314d574c3148386ef4bf4b5c2de63712297 # Parent 4011e4ee3151965406f9ffccdbd1966f023f70e4 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 diff -r 4011e4ee3151 -r 282d1314d574 sat/plugins/plugin_xep_0234.py --- 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 diff -r 4011e4ee3151 -r 282d1314d574 sat/plugins/plugin_xep_0329.py --- 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)