Mercurial > libervia-backend
diff sat/plugins/plugin_xep_0234.py @ 3040:fee60f17ebac
jp: jp asyncio port:
/!\ this commit is huge. Jp is temporarily not working with `dbus` bridge /!\
This patch implements the port of jp to asyncio, so it is now correctly using the bridge
asynchronously, and it can be used with bridges like `pb`. This also simplify the code,
notably for things which were previously implemented with many callbacks (like pagination
with RSM).
During the process, some behaviours have been modified/fixed, in jp and backends, check
diff for details.
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 25 Sep 2019 08:56:41 +0200 |
parents | ab2696e34d29 |
children | 9d0df638c8b4 |
line wrap: on
line diff
--- a/sat/plugins/plugin_xep_0234.py Wed Sep 25 08:53:38 2019 +0200 +++ b/sat/plugins/plugin_xep_0234.py Wed Sep 25 08:56:41 2019 +0200 @@ -55,7 +55,7 @@ C.PI_DESCRIPTION: _("""Implementation of Jingle File Transfer"""), } -EXTRA_ALLOWED = {"path", "namespace", "file_desc", "file_hash"} +EXTRA_ALLOWED = {"path", "namespace", "file_desc", "file_hash", "hash_algo"} Range = namedtuple("Range", ("offset", "length")) @@ -106,7 +106,7 @@ # generic methods - def buildFileElement(self, name, file_hash=None, hash_algo=None, size=None, + def buildFileElement(self, name=None, file_hash=None, hash_algo=None, size=None, mime_type=None, desc=None, modified=None, transfer_range=None, path=None, namespace=None, file_elt=None, **kwargs): """Generate a <file> element with available metadata @@ -177,14 +177,8 @@ file_data.update(kwargs) return self.buildFileElement(**file_data) - def parseFileElement( - self, - file_elt, - file_data=None, - given=False, - parent_elt=None, - keep_empty_range=False, - ): + def parseFileElement(self, file_elt, file_data=None, given=False, parent_elt=None, + keep_empty_range=False,): """Parse a <file> element and file dictionary accordingly @param file_data(dict, None): dict where the data will be set @@ -194,10 +188,12 @@ @param given(bool): if True, prefix hash key with "given_" @param parent_elt(domish.Element, None): parent of the file element if set, file_elt must not be set - @param keep_empty_range(bool): if True, keep empty range (i.e. range when offset and length are None) - empty range are useful to know if a peer_jid can handle range + @param keep_empty_range(bool): if True, keep empty range (i.e. range when offset + and length are None). + Empty range is useful to know if a peer_jid can handle range @return (dict): file_data - @trigger XEP-0234_parseFileElement(file_elt, file_data): can be used to parse new elements + @trigger XEP-0234_parseFileElement(file_elt, file_data): can be used to parse new + elements @raise exceptions.NotFound: there is not <file> element in parent_elt @raise exceptions.DataError: if file_elt uri is not NS_JINGLE_FT """ @@ -230,7 +226,7 @@ # we don't want to go to parent dir when joining to a path name = "--" file_data["name"] = name - elif name is not None and "/" in name or "\\" in name: + elif name is not None and ("/" in name or "\\" in name): file_data["name"] = regex.pathEscape(name) try: @@ -335,15 +331,8 @@ defer.returnValue(progress_id) def _fileJingleRequest( - self, - peer_jid, - filepath, - name="", - file_hash="", - hash_algo="", - extra=None, - profile=C.PROF_KEY_NONE, - ): + self, peer_jid, filepath, name="", file_hash="", hash_algo="", extra=None, + profile=C.PROF_KEY_NONE): client = self.host.getClient(profile) return self.fileJingleRequest( client, @@ -357,15 +346,8 @@ @defer.inlineCallbacks def fileJingleRequest( - self, - client, - peer_jid, - filepath, - name=None, - file_hash=None, - hash_algo=None, - extra=None, - ): + self, client, peer_jid, filepath, name=None, file_hash=None, hash_algo=None, + extra=None): """Request a file using jingle file transfer @param peer_jid(jid.JID): destinee jid @@ -568,6 +550,7 @@ d.addCallback(gotConfirmation) return d + @defer.inlineCallbacks def jingleHandler(self, client, action, session, content_name, desc_elt): content_data = session["contents"][content_name] application_data = content_data["application_data"] @@ -579,7 +562,7 @@ next(file_elt.elements(NS_JINGLE_FT, "range")) except StopIteration: # initiator doesn't manage <range>, but we do so we advertise it - # Â FIXME: to be checked + # FIXME: to be checked log.debug("adding <range> element") file_elt.addElement("range") elif action == self._j.A_SESSION_ACCEPT: @@ -596,21 +579,32 @@ size = int(str(size_elt)) except (StopIteration, ValueError): size = None - # XXX: hash security is not critical here, so we just take the higher mandatory one + # XXX: hash security is not critical here, so we just take the higher + # mandatory one hasher = file_data["hash_hasher"] = self._hash.getHasher() - content_data["stream_object"] = stream.FileStreamObject( - self.host, - client, - file_path, - mode="wb", - uid=self.getProgressId(session, content_name), - size=size, - data_cb=lambda data: hasher.update(data), - ) + progress_id = self.getProgressId(session, content_name) + try: + content_data["stream_object"] = stream.FileStreamObject( + self.host, + client, + file_path, + mode="wb", + uid=progress_id, + size=size, + data_cb=lambda data: hasher.update(data), + ) + except Exception as e: + self.host.bridge.progressError( + progress_id, C.PROGRESS_ERROR_FAILED, client.profile + ) + yield self._j.terminate( + client, self._j.REASON_FAILED_APPLICATION, session) + raise e else: # we are sending the file size = file_data["size"] - # XXX: hash security is not critical here, so we just take the higher mandatory one + # XXX: hash security is not critical here, so we just take the higher + # mandatory one hasher = file_data["hash_hasher"] = self._hash.getHasher() content_data["stream_object"] = stream.FileStreamObject( self.host, @@ -625,7 +619,7 @@ finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args) else: log.warning("FIXME: unmanaged action {}".format(action)) - return desc_elt + defer.returnValue(desc_elt) def jingleSessionInfo(self, client, action, session, content_name, jingle_elt): """Called on session-info action @@ -679,6 +673,16 @@ self.host.bridge.progressError( progress_id, C.PROGRESS_ERROR_DECLINED, client.profile ) + elif not jingle_elt.success: + progress_id = self.getProgressId(session, content_name) + first_child = jingle_elt.firstChildElement() + if first_child is not None: + reason = first_child.name + else: + reason = C.PROGRESS_ERROR_FAILED + self.host.bridge.progressError( + progress_id, reason, client.profile + ) def _sendCheckSum(self, client, session, content_name, content_data): """Send the session-info with the hash checksum""" @@ -721,10 +725,10 @@ return True return False hasher = file_data["hash_hasher"] - hash_ = hasher.hexdigest().encode('utf-8') + hash_ = hasher.hexdigest() if hash_ == given_hash: - log.info("Hash checked, file was successfully transfered: {}".format(hash_)) + log.info(f"Hash checked, file was successfully transfered: {hash_}") progress_metadata = { "hash": hash_, "hash_algo": file_data["hash_algo"],