# HG changeset patch # User Goffi # Date 1453490657 -3600 # Node ID a19161bb3ff7479249b55202c7354fa1eca31bb8 # Parent 1424cc6f8e987034764ffacd20c09123a592d94e plugin upload, XEP-0363: splitted fileUpload in fileUpload + upload: fileUpload is used by external frontends, while upload can be used by frontends. upload return in addition to the progress_id a download_d Deferred which fire with URI when file is uploaded. changed option ignore-tls-errors to ignore_tls_errors. diff -r 1424cc6f8e98 -r a19161bb3ff7 frontends/src/jp/cmd_file.py --- a/frontends/src/jp/cmd_file.py Fri Jan 22 20:24:17 2016 +0100 +++ b/frontends/src/jp/cmd_file.py Fri Jan 22 20:24:17 2016 +0100 @@ -276,7 +276,7 @@ self.full_dest_jid = self.host.get_full_jid(self.args.jid) if self.args.jid is not None else '' options = {} if self.args.ignore_tls_errors: - options['ignore-tls-errors'] = C.BOOL_TRUE + options['ignore_tls_errors'] = C.BOOL_TRUE path = os.path.abspath(file_) self.host.bridge.fileUpload(path, '', self.full_dest_jid, options, self.profile, callback=lambda pid, file_=file_: self.gotId(pid, file_), errback=self.error) diff -r 1424cc6f8e98 -r a19161bb3ff7 src/plugins/plugin_misc_upload.py --- a/src/plugins/plugin_misc_upload.py Fri Jan 22 20:24:17 2016 +0100 +++ b/src/plugins/plugin_misc_upload.py Fri Jan 22 20:24:17 2016 +0100 @@ -41,7 +41,7 @@ UPLOADING = D_(u'Please select a file to upload') UPLOADING_TITLE = D_(u'File upload') -BOOL_OPTIONS = ('ignore-tls-errors',) +BOOL_OPTIONS = ('ignore_tls_errors',) class UploadPlugin(object): @@ -54,6 +54,7 @@ self._upload_callbacks = [] def _fileUpload(self, filepath, filename, upload_jid_s='', options=None, profile=C.PROF_KEY_NONE): + client = self.host.getClient(profile) upload_jid = jid.JID(upload_jid_s) if upload_jid_s else None if options is None: options = {} @@ -64,10 +65,31 @@ except KeyError: pass - return self.fileUpload(filepath, filename or None, upload_jid, options or None, profile) + return self.fileUpload(client, filepath, filename or None, upload_jid, options or None) @defer.inlineCallbacks - def fileUpload(self, filepath, filename, upload_jid, options, profile=C.PROF_KEY_NONE): + def fileUpload(self, client, filepath, filename, upload_jid, options): + """Send a file using best available method + + parameters are the same as for [upload] + @return (dict): action dictionary, with progress id in case of success, else xmlui message + """ + def uploadCb(data): + progress_id, dummy = data + return {'progress': progress_id} + + def uploadEb(fail): + msg = unicode(fail) + log.warning(msg) + return {'xmlui': xml_tools.note(u"Can't upload file", msg, C.XMLUI_DATA_LVL_WARNING).toXml()} + + d = self.upload(filepath, filename, upload_jid, options, client.profile) + d.addCallback(uploadCb) + d.addErrback(uploadEb) + return d + + @defer.inlineCallbacks + def upload(self, client, filepath, filename=None, upload_jid=None, options=None): """Send a file using best available method @param filepath(str): absolute path to the file @@ -76,26 +98,28 @@ @param upload_jid(jid.JID, None): upload capable entity jid, or None to use autodetected, if possible @param options(dict): option to use for the upload, may be: - - ignore-tls-errors(bool): True to ignore SSL/TLS certificate verification + - ignore_tls_errors(bool): True to ignore SSL/TLS certificate verification used only if HTTPS transport is needed @param profile: %(doc_profile)s - @return (dict): action dictionary, with progress id in case of success, else xmlui message + @return (tuple[unicode,D(unicode)]): progress_id and a Deferred which fire download URL + when upload is finished """ + if options is None: + options = {} if not os.path.isfile(filepath): raise exceptions.DataError(u"The given path doesn't link to a file") for method_name, available_cb, upload_cb, priority in self._upload_callbacks: try: - upload_jid = yield available_cb(upload_jid, profile) + upload_jid = yield available_cb(upload_jid, client.profile) except exceptions.NotFound: continue # no entity managing this extension found - log.info(u"{name} method will be used to upload the file".format(name=method_name)) - progress_id = yield defer.maybeDeferred(upload_cb, filepath, filename, upload_jid, options, profile) - defer.returnValue({'progress': progress_id}) - # if we reach this point, no entity handling any known upload method has been found - msg = u"Can't find any method to upload a file" - log.warning(msg) - defer.returnValue({'xmlui': xml_tools.note(u"Can't upload file", msg, C.XMLUI_DATA_LVL_WARNING).toXml()}) + log.info(u"{name} method will be used to upload the file".format(name=method_name)) + progress_id_d, download_d = yield defer.maybeDeferred(upload_cb, filepath, filename, upload_jid, options, client.profile) + progress_id = yield progress_id_d + defer.returnValue((progress_id, download_d)) + + raise exceptions.NotFound(u"Can't find any method to upload a file") def register(self, method_name, available_cb, upload_cb, priority=0): """Register a fileUploading method @@ -105,7 +129,10 @@ the callback must take two arguments: upload_jid (can be None) and profile the callback must return the first entity found (being upload_jid or one of its components) exceptions.NotFound must be raised if no entity has been found - @param upload_cb(callable): method to upload a file (must have the same signature as [fileUpload]) + @param upload_cb(callable): method to upload a file + must have the same signature as [fileUpload] + must return a tuple with progress_id and a Deferred which fire download URL when + upload is finished @param priority(int): pririoty of this method, the higher available will be used """ assert method_name @@ -113,7 +140,7 @@ if method_name == data[0]: raise exceptions.ConflictError(u'A method with this name is already registered') self._upload_callbacks.append((method_name, available_cb, upload_cb, priority)) - self._upload_callbacks.sort(key=lambda data: data[2], reverse=True) + self._upload_callbacks.sort(key=lambda data: data[3], reverse=True) def unregister(self, method_name): for idx, data in enumerate(self._upload_callbacks): diff -r 1424cc6f8e98 -r a19161bb3ff7 src/plugins/plugin_xep_0363.py --- a/src/plugins/plugin_xep_0363.py Fri Jan 22 20:24:17 2016 +0100 +++ b/src/plugins/plugin_xep_0363.py Fri Jan 22 20:24:17 2016 +0100 @@ -123,7 +123,8 @@ def _fileHTTPUpload(self, filepath, filename='', upload_jid='', ignore_tls_errors=False, profile=C.PROF_KEY_NONE): assert os.path.isabs(filepath) and os.path.isfile(filepath) - return self.fileHTTPUpload(filepath, filename or None, jid.JID(upload_jid) if upload_jid else None, {'ignore-tls-errors': ignore_tls_errors}, profile) + progress_id_d, dummy = self.fileHTTPUpload(filepath, filename or None, jid.JID(upload_jid) if upload_jid else None, {'ignore_tls_errors': ignore_tls_errors}, profile) + return progress_id_d def fileHTTPUpload(self, filepath, filename=None, upload_jid=None, options=None, profile=C.PROF_KEY_NONE): """upload a file through HTTP @@ -136,29 +137,32 @@ @param options(dict): options where key can be: - ignore_tls_errors(bool): if True, SSL certificate will not be checked @param profile: %(doc_profile)s - @return (D(unicode)): progress id + @return (D(tuple[D(unicode), D(unicode)])): progress id and Deferred which fire download URL """ if options is None: options = {} - ignore_tls_errors = options.get('ignore-tls-errors', False) + ignore_tls_errors = options.get('ignore_tls_errors', False) client = self.host.getClient(profile) filename = filename or os.path.basename(filepath) size = os.path.getsize(filepath) progress_id_d = defer.Deferred() + download_d = defer.Deferred() d = self.getSlot(client, filename, size, upload_jid=upload_jid) - d.addCallbacks(self._getSlotCb, self._getSlotEb, (client, progress_id_d, filepath, size, ignore_tls_errors), None, (client, progress_id_d)) - return progress_id_d + d.addCallbacks(self._getSlotCb, self._getSlotEb, (client, progress_id_d, download_d, filepath, size, ignore_tls_errors), None, (client, progress_id_d, download_d)) + return progress_id_d, download_d - def _getSlotEb(self, fail, client, progress_id_d): + def _getSlotEb(self, fail, client, progress_id_d, download_d): """an error happened while trying to get slot""" log.warning(u"Can't get upload slot: {reason}".format(reason=fail.value)) progress_id_d.errback(fail) + download_d.errback(fail) - def _getSlotCb(self, slot, client, progress_id_d, path, size, ignore_tls_errors=False): + def _getSlotCb(self, slot, client, progress_id_d, download_d, path, size, ignore_tls_errors=False): """Called when slot is received, try to do the upload @param slot(Slot): slot instance with the get and put urls @param progress_id_d(defer.Deferred): Deferred to call when progress_id is known + @param progress_id_d(defer.Deferred): Deferred to call with URL when upload is done @param path(str): path to the file to upload @param size(int): size of the file to upload @param ignore_tls_errors(bool): ignore TLS certificate is True @@ -173,10 +177,10 @@ else: agent = http_client.Agent(reactor) d = agent.request('PUT', slot.put.encode('utf-8'), http_headers.Headers({'User-Agent': [C.APP_NAME.encode('utf-8')]}), file_producer) - d.addCallbacks(self._uploadCb, self._uploadEb, (sat_file, slot), None, (sat_file,)) + d.addCallbacks(self._uploadCb, self._uploadEb, (sat_file, slot, download_d), None, (sat_file, download_d)) return d - def _uploadCb(self, dummy, sat_file, slot): + def _uploadCb(self, dummy, sat_file, slot, download_d): """Called once file is successfully uploaded @param sat_file(SatFile): file used for the upload @@ -185,13 +189,15 @@ """ log.info(u"HTTP upload finished") sat_file.progressFinished({'url': slot.get}) + download_d.callback(slot.get) - def _uploadEb(self, fail, sat_file): + def _uploadEb(self, fail, sat_file, download_d): """Called on unsuccessful upload @param sat_file(SatFile): file used for the upload should be closed, be is needed to send the progressError signal """ + download_d.errback(fail) try: wrapped_fail = fail.value.reasons[0] except (AttributeError, IndexError):