commit 23d4992265cb264c65f37c4443cc02275d7d349a
parent 4c9f389aa8f4f41a51d60a60dd9b7a91b9422c4c
Author: Dan Stillman <dstillman@zotero.org>
Date: Sat, 29 Jul 2017 22:11:56 -0400
Fix Zotero.Utilities.Internal.getAsyncInputStream(), used by Timeline
Diffstat:
1 file changed, 46 insertions(+), 86 deletions(-)
diff --git a/chrome/content/zotero/xpcom/utilities_internal.js b/chrome/content/zotero/xpcom/utilities_internal.js
@@ -639,10 +639,6 @@ Zotero.Utilities.Internal = {
* @return {nsIAsyncInputStream}
*/
getAsyncInputStream: function (gen, onError) {
- const funcName = 'getAsyncInputStream';
- const maxOutOfSequenceSeconds = 10;
- const outOfSequenceDelay = 50;
-
// Initialize generator if necessary
var g = gen.next ? gen : gen();
var seq = 0;
@@ -656,92 +652,56 @@ Zotero.Utilities.Internal = {
os.init(pipe.outputStream, 'utf-8', 0, 0x0000);
- pipe.outputStream.asyncWait({
- onOutputStreamReady: function (aos) {
- //Zotero.debug("Output stream is ready");
-
- let currentSeq = seq++;
-
- Zotero.spawn(function* () {
- var lastVal;
- var error = false;
-
- while (true) {
- var data;
-
- try {
- let result = g.next(lastVal);
-
- if (result.done) {
- Zotero.debug("No more data to write");
- aos.close();
- return;
- }
- // If a promise is yielded, wait for it and pass on its value
- if (result.value.then) {
- lastVal = yield result.value;
- continue;
- }
- // Otherwise use the return value
- data = result.value;
- break;
- }
- catch (e) {
- Zotero.debug(e, 1);
-
- if (onError) {
- error = e;
- data = onError();
- break;
- }
-
- Zotero.debug("Closing input stream");
- 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 + "')");
+ function onOutputStreamReady(aos) {
+ let currentSeq = seq++;
+
+ var maybePromise = processNextValue();
+ // If generator returns a promise, wait for it
+ if (maybePromise.then) {
+ maybePromise.then(() => onOutputStreamReady(aos));
+ }
+ // 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 {
+ var result = g.next(lastVal);
+ if (result.done) {
+ Zotero.debug("No more data to write");
+ return false;
+ }
+ if (result.value.then) {
+ return result.value.then(val => processNextValue(val));
+ }
+ if (typeof result.value != 'string') {
+ throw new Error("Data is not a string or promise (" + result.value + ")");
+ }
+ os.writeString(result.value);
+ return true;
+ }
+ catch (e) {
+ Zotero.logError(e);
+ if (onError) {
+ try {
+ os.writeString(onError(e));
}
-
- // 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--;
+ catch (e) {
+ Zotero.logError(e);
}
-
- // 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;
},