Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0329.py @ 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 | 26edcf3a30eb |
children | 56f94936df1e |
comparison
equal
deleted
inserted
replaced
2588:4011e4ee3151 | 2589:282d1314d574 |
---|---|
95 | 95 |
96 def __contains__(self, item): | 96 def __contains__(self, item): |
97 return self.children.__contains__(item) | 97 return self.children.__contains__(item) |
98 | 98 |
99 def __iter__(self): | 99 def __iter__(self): |
100 return self.children.__iter__ | 100 return self.children.__iter__() |
101 | 101 |
102 def iteritems(self): | 102 def iteritems(self): |
103 return self.children.iteritems() | 103 return self.children.iteritems() |
104 | 104 |
105 def itervalues(self): | |
106 return self.children.itervalues() | |
107 | |
105 def getOrCreate(self, name, type_=TYPE_VIRTUAL, access=None): | 108 def getOrCreate(self, name, type_=TYPE_VIRTUAL, access=None): |
106 """get a node or create a virtual one and return it""" | 109 """get a node or create a virtual node and return it""" |
107 if access is None: | 110 if access is None: |
108 access = {C.ACCESS_PERM_READ: {KEY_TYPE: C.ACCESS_TYPE_PUBLIC}} | 111 access = {C.ACCESS_PERM_READ: {KEY_TYPE: C.ACCESS_TYPE_PUBLIC}} |
109 try: | 112 try: |
110 return self.children[name] | 113 return self.children[name] |
111 except KeyError: | 114 except KeyError: |
115 def addChild(self, node): | 118 def addChild(self, node): |
116 if node.parent is not None: | 119 if node.parent is not None: |
117 raise exceptions.ConflictError(_(u"a node can't have several parents")) | 120 raise exceptions.ConflictError(_(u"a node can't have several parents")) |
118 node.parent = self | 121 node.parent = self |
119 self.children[node.name] = node | 122 self.children[node.name] = node |
123 | |
124 def removeFromParent(self): | |
125 try: | |
126 del self.parent.children[self.name] | |
127 except TypeError: | |
128 raise exceptions.InternalError(u'trying to remove a node from inexisting parent') | |
129 except KeyError: | |
130 raise exceptions.InternalError(u"node not found in parent's children") | |
131 self.parent = None | |
120 | 132 |
121 def _checkNodePermission(self, client, node, perms, peer_jid): | 133 def _checkNodePermission(self, client, node, perms, peer_jid): |
122 """Check access to this node for peer_jid | 134 """Check access to this node for peer_jid |
123 | 135 |
124 @param node(SharedNode): node to check access | 136 @param node(SharedNode): node to check access |
190 if not node.checkPermissions(client, peer_jid, perms = perms): | 202 if not node.checkPermissions(client, peer_jid, perms = perms): |
191 raise exceptions.PermissionError(u"permission denied") | 203 raise exceptions.PermissionError(u"permission denied") |
192 | 204 |
193 return node, u'/'.join(path_elts) | 205 return node, u'/'.join(path_elts) |
194 | 206 |
207 def findByLocalPath(self, path): | |
208 """retrieve nodes linking to local path | |
209 | |
210 @return (list[ShareNode]): found nodes associated to path | |
211 @raise exceptions.NotFound: no node has been found with this path | |
212 """ | |
213 shared_paths = self.getSharedPaths() | |
214 try: | |
215 return shared_paths[path] | |
216 except KeyError: | |
217 raise exceptions.NotFound | |
218 | |
219 def _getSharedPaths(self, node, paths): | |
220 if node.type == TYPE_VIRTUAL: | |
221 for node in node.itervalues(): | |
222 self._getSharedPaths(node, paths) | |
223 elif node.type == TYPE_PATH: | |
224 paths.setdefault(node.path, []).append(node) | |
225 else: | |
226 raise exceptions.InternalError(u'unknown node type: {type}'.format( | |
227 type = node.type)) | |
228 | |
229 def getSharedPaths(self): | |
230 """retrieve nodes by shared path | |
231 | |
232 this method will retrieve recursively shared path in children of this node | |
233 @return (dict): map from shared path to list of nodes | |
234 """ | |
235 if self.type == TYPE_PATH: | |
236 raise exceptions.InternalError("getSharedPaths must be used on a virtual node") | |
237 paths = {} | |
238 self._getSharedPaths(self, paths) | |
239 return paths | |
240 | |
195 | 241 |
196 class XEP_0329(object): | 242 class XEP_0329(object): |
197 | 243 |
198 def __init__(self, host): | 244 def __init__(self, host): |
199 log.info(_("File Information Sharing initialization")) | 245 log.info(_("File Information Sharing initialization")) |
200 self.host = host | 246 self.host = host |
201 ShareNode.host = host | 247 ShareNode.host = host |
202 self._h = host.plugins['XEP-0300'] | 248 self._h = host.plugins['XEP-0300'] |
203 self._jf = host.plugins['XEP-0234'] | 249 self._jf = host.plugins['XEP-0234'] |
204 host.bridge.addMethod("FISList", ".plugin", in_sign='ssa{ss}s', out_sign='aa{ss}', method=self._listFiles, async=True) | 250 host.bridge.addMethod("FISList", ".plugin", in_sign='ssa{ss}s', out_sign='aa{ss}', method=self._listFiles, async=True) |
251 host.bridge.addMethod("FISLocalSharesGet", ".plugin", in_sign='s', out_sign='as', method=self._localSharesGet) | |
205 host.bridge.addMethod("FISSharePath", ".plugin", in_sign='ssss', out_sign='s', method=self._sharePath) | 252 host.bridge.addMethod("FISSharePath", ".plugin", in_sign='ssss', out_sign='s', method=self._sharePath) |
253 host.bridge.addMethod("FISUnsharePath", ".plugin", in_sign='ss', out_sign='', method=self._unsharePath) | |
254 host.bridge.addSignal("FISSharedPathNew", ".plugin", signature='sss') | |
255 host.bridge.addSignal("FISSharedPathRemoved", ".plugin", signature='ss') | |
206 host.trigger.add("XEP-0234_fileSendingRequest", self._fileSendingRequestTrigger) | 256 host.trigger.add("XEP-0234_fileSendingRequest", self._fileSendingRequestTrigger) |
207 host.registerNamespace('fis', NS_FIS) | 257 host.registerNamespace('fis', NS_FIS) |
208 | 258 |
209 def getHandler(self, client): | 259 def getHandler(self, client): |
210 return XEP_0329_handler(self) | 260 return XEP_0329_handler(self) |
502 query_elt['node'] = path | 552 query_elt['node'] = path |
503 d = iq_elt.send() | 553 d = iq_elt.send() |
504 d.addCallback(self._parseResult) | 554 d.addCallback(self._parseResult) |
505 return d | 555 return d |
506 | 556 |
557 def _localSharesGet(self, profile): | |
558 client = self.host.getClient(profile) | |
559 return self.localSharesGet(client) | |
560 | |
561 def localSharesGet(self, client): | |
562 return client._XEP_0329_root_node.getSharedPaths().keys() | |
563 | |
507 def _sharePath(self, name, path, access, profile): | 564 def _sharePath(self, name, path, access, profile): |
508 client = self.host.getClient(profile) | 565 client = self.host.getClient(profile) |
509 access= json.loads(access) | 566 access= json.loads(access) |
510 return self.sharePath(client, name or None, path, access) | 567 return self.sharePath(client, name or None, path, access) |
511 | 568 |
514 raise exceptions.ClientTypeError | 571 raise exceptions.ClientTypeError |
515 if not os.path.exists(path): | 572 if not os.path.exists(path): |
516 raise ValueError(_(u"This path doesn't exist!")) | 573 raise ValueError(_(u"This path doesn't exist!")) |
517 if not path or not path.strip(u' /'): | 574 if not path or not path.strip(u' /'): |
518 raise ValueError(_(u"A path need to be specified")) | 575 raise ValueError(_(u"A path need to be specified")) |
576 if not isinstance(access, dict): | |
577 raise ValueError(_(u'access must be a dict')) | |
519 | 578 |
520 node = client._XEP_0329_root_node | 579 node = client._XEP_0329_root_node |
521 node_type = TYPE_PATH | 580 node_type = TYPE_PATH |
522 if os.path.isfile(path): | 581 if os.path.isfile(path): |
523 # we have a single file, the workflow is diferrent as we store all single files in the same dir | 582 # we have a single file, the workflow is diferrent as we store all single files in the same dir |
525 | 584 |
526 if not name: | 585 if not name: |
527 name = os.path.basename(path.rstrip(u' /')) | 586 name = os.path.basename(path.rstrip(u' /')) |
528 if not name: | 587 if not name: |
529 raise exceptions.InternalError(_(u"Can't find a proper name")) | 588 raise exceptions.InternalError(_(u"Can't find a proper name")) |
530 | |
531 if not isinstance(access, dict): | |
532 raise ValueError(_(u'access must be a dict')) | |
533 | 589 |
534 if name in node or name == SINGLE_FILES_DIR: | 590 if name in node or name == SINGLE_FILES_DIR: |
535 idx = 1 | 591 idx = 1 |
536 new_name = name + '_' + unicode(idx) | 592 new_name = name + '_' + unicode(idx) |
537 while new_name in node: | 593 while new_name in node: |
540 name = new_name | 596 name = new_name |
541 log.info(_(u"A directory with this name is already shared, renamed to {new_name} [{profile}]".format( | 597 log.info(_(u"A directory with this name is already shared, renamed to {new_name} [{profile}]".format( |
542 new_name=new_name, profile=client.profile))) | 598 new_name=new_name, profile=client.profile))) |
543 | 599 |
544 ShareNode(name=name, parent=node, type_=node_type, access=access, path=path) | 600 ShareNode(name=name, parent=node, type_=node_type, access=access, path=path) |
601 self.host.bridge.FISSharedPathNew(path, name, client.profile) | |
545 return name | 602 return name |
603 | |
604 def _unsharePath(self, path, profile): | |
605 client = self.host.getClient(profile) | |
606 return self.unsharePath(client, path) | |
607 | |
608 def unsharePath(self, client, path): | |
609 nodes = client._XEP_0329_root_node.findByLocalPath(path) | |
610 for node in nodes: | |
611 node.removeFromParent() | |
612 self.host.bridge.FISSharedPathRemoved(path, client.profile) | |
546 | 613 |
547 | 614 |
548 class XEP_0329_handler(xmlstream.XMPPHandler): | 615 class XEP_0329_handler(xmlstream.XMPPHandler): |
549 implements(iwokkel.IDisco) | 616 implements(iwokkel.IDisco) |
550 | 617 |