Fix Zotero.Utilities.Internal.getAsyncInputStream(), used by Timeline

This commit is contained in:
Dan Stillman 2017-07-29 22:11:56 -04:00
parent 4c9f389aa8
commit 23d4992265

View File

@ -639,10 +639,6 @@ Zotero.Utilities.Internal = {
* @return {nsIAsyncInputStream} * @return {nsIAsyncInputStream}
*/ */
getAsyncInputStream: function (gen, onError) { getAsyncInputStream: function (gen, onError) {
const funcName = 'getAsyncInputStream';
const maxOutOfSequenceSeconds = 10;
const outOfSequenceDelay = 50;
// Initialize generator if necessary // Initialize generator if necessary
var g = gen.next ? gen : gen(); var g = gen.next ? gen : gen();
var seq = 0; var seq = 0;
@ -656,92 +652,56 @@ Zotero.Utilities.Internal = {
os.init(pipe.outputStream, 'utf-8', 0, 0x0000); os.init(pipe.outputStream, 'utf-8', 0, 0x0000);
pipe.outputStream.asyncWait({ function onOutputStreamReady(aos) {
onOutputStreamReady: function (aos) {
//Zotero.debug("Output stream is ready");
let currentSeq = seq++; let currentSeq = seq++;
Zotero.spawn(function* () { var maybePromise = processNextValue();
var lastVal; // If generator returns a promise, wait for it
var error = false; if (maybePromise.then) {
maybePromise.then(() => onOutputStreamReady(aos));
while (true) { }
var data; // If more data, tell stream we're ready
else if (maybePromise) {
aos.asyncWait({ onOutputStreamReady }, 0, 0, Zotero.mainThread);
}
// Otherwise close the stream
else {
aos.close();
}
};
function processNextValue(lastVal) {
try { try {
let result = g.next(lastVal); var result = g.next(lastVal);
if (result.done) { if (result.done) {
Zotero.debug("No more data to write"); Zotero.debug("No more data to write");
aos.close(); return false;
return;
} }
// If a promise is yielded, wait for it and pass on its value
if (result.value.then) { if (result.value.then) {
lastVal = yield result.value; return result.value.then(val => processNextValue(val));
continue;
} }
// Otherwise use the return value if (typeof result.value != 'string') {
data = result.value; throw new Error("Data is not a string or promise (" + result.value + ")");
break; }
os.writeString(result.value);
return true;
} }
catch (e) { catch (e) {
Zotero.debug(e, 1); Zotero.logError(e);
if (onError) { if (onError) {
error = e; try {
data = onError(); os.writeString(onError(e));
break;
} }
catch (e) {
Zotero.debug("Closing input stream"); Zotero.logError(e);
aos.close();
throw e;
} }
} }
if (error) {
Zotero.debug("Closing input stream");
aos.close();
throw error;
}
if (typeof data != 'string') {
throw new Error("Yielded value is not a string or promise in " + funcName
+ " ('" + data + "')");
}
// Make sure that we're writing to the stream in order, in case
// onOutputStreamReady is called again before the last promise completes.
// If not in order, wait a bit and try again.
var maxTries = Math.floor(maxOutOfSequenceSeconds * 1000 / outOfSequenceDelay);
while (currentSeq != seq - 1) {
if (maxTries <= 0) {
throw new Error("Next promise took too long to finish in " + funcName);
}
Zotero.debug("Promise finished out of sequence in " + funcName
+ "-- waiting " + outOfSequenceDelay + " ms");
yield Zotero.Promise.delay(outOfSequenceDelay);
maxTries--;
}
// Write to stream
Zotero.debug("Writing " + data.length + " characters");
os.writeString(data);
// Wait until stream is ready for more
aos.asyncWait(this, 0, 0, null);
}, this)
.catch(function (e) {
Zotero.debug("Error getting data for async stream", 1);
Components.utils.reportError(e);
Zotero.debug(e, 1);
os.close(); os.close();
}); return false;
}
} }
}, 0, 0, null);
pipe.outputStream.asyncWait({ onOutputStreamReady }, 0, 0, Zotero.mainThread);
return pipe.inputStream; return pipe.inputStream;
}, },