New implementation of a download function #2216

This resolves a problem where, in certain scenarios,
Zotero.file.download throws an exception even though file is
successfully downloaded.

Furthermore this new download function should be more memory-efficient,
improving performance when dealing with large files.
This commit is contained in:
Tom Najdek 2021-10-02 00:34:51 +02:00
parent a08c3dee14
commit a745cde2cf
No known key found for this signature in database
GPG key ID: EEC61A7B4C667D77

View file

@ -446,8 +446,7 @@ Zotero.File = new function(){
});
};
this.download = Zotero.Promise.coroutine(function* (uri, path) {
this.download = async function (uri, path) {
var uriStr = uri.spec || uri;
Zotero.debug(`Saving ${uriStr} to ${path.pathQueryRef || path}`);
@ -459,7 +458,24 @@ Zotero.File = new function(){
}
var deferred = Zotero.Promise.defer();
NetUtil.asyncFetch(uri, function (is, status, request) {
const uri_ = NetUtil.ioService.newURI(uri);
const inputChannel = NetUtil.ioService.newChannelFromURI(uri_);
const outputChannel = FileUtils.openSafeFileOutputStream(new FileUtils.File(path));
const pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
pipe.init(true, true, 0, 0xffffffff, null);
let listener = Cc[
"@mozilla.org/network/simple-stream-listener;1"
].createInstance(Ci.nsISimpleStreamListener);
listener.init(pipe.outputStream, {
onStartRequest(request) {
// NOTE: This noop callback is required, do not remove.
},
onStopRequest(request, status) {
const responseStatus = 'responseStatus' in request ? request.responseStatus : null;
pipe.outputStream.close();
if (!Components.isSuccessCode(status)) {
Zotero.logError(status);
let msg = Zotero.getString('sync.error.checkConnection');
@ -472,18 +488,22 @@ Zotero.File = new function(){
deferred.reject(new Error(msg));
return;
}
if (request.responseStatus != 200) {
let msg = `Download failed with response code ${request.responseStatus}`;
if (responseStatus != 200) {
let msg = `Download failed with response code ${responseStatus}`;
Zotero.logError(msg);
deferred.reject(new Error(msg));
return;
}
deferred.resolve(is);
});
var is = yield deferred.promise;
yield Zotero.File.putContentsAsync(path, is);
}
});
NetUtil.asyncCopy(pipe.inputStream, outputChannel, function(aResult) {
deferred.resolve();
});
inputChannel.asyncOpen(listener, null);
return deferred.promise;
};
/**
* Rename file within its parent directory