async-ify more functions, and await completion

Where feasible I put the await at the end of the function to
minimize the impact on latency.

My motivation for this change: Eliminate a race condition in tests I
am writing.
This commit is contained in:
Richard Hansen 2020-09-16 21:06:15 -04:00 committed by John McLear
parent 45ec8326f0
commit 3365e944bf
8 changed files with 78 additions and 70 deletions

View file

@ -203,11 +203,10 @@ exports.setText = async function(padID, text)
// get the pad
let pad = await getPadSafe(padID, true);
// set the text
pad.setText(text);
// update the clients on the pad
padMessageHandler.updatePadClients(pad);
await Promise.all([
pad.setText(text),
padMessageHandler.updatePadClients(pad),
]);
}
/**
@ -226,12 +225,11 @@ exports.appendText = async function(padID, text)
throw new customError("text is not a string", "apierror");
}
// get and update the pad
let pad = await getPadSafe(padID, true);
pad.appendText(text);
// update the clients on the pad
padMessageHandler.updatePadClients(pad);
await Promise.all([
pad.appendText(text),
padMessageHandler.updatePadClients(pad),
]);
}
/**
@ -287,7 +285,7 @@ exports.setHTML = async function(padID, html)
// add a new changeset with the new html to the pad
try {
importHtml.setPadHTML(pad, cleanText(html));
await importHtml.setPadHTML(pad, cleanText(html));
} catch (e) {
throw new customError("HTML is malformed", "apierror");
}
@ -373,7 +371,7 @@ exports.appendChatMessage = async function(padID, text, authorID, time)
// @TODO - missing getPadSafe() call ?
// save chat message to database and send message to all connected clients
padMessageHandler.sendChatMessageToPadClients(time, authorID, text, padID);
await padMessageHandler.sendChatMessageToPadClients(time, authorID, text, padID);
}
/*****************/
@ -454,7 +452,7 @@ exports.saveRevision = async function(padID, rev)
}
let author = await authorManager.createAuthor('API');
pad.addSavedRevision(rev, author.authorID, 'Saved through API call');
await pad.addSavedRevision(rev, author.authorID, 'Saved through API call');
}
/**
@ -575,11 +573,10 @@ exports.restoreRevision = async function(padID, rev)
var changeset = builder.toString();
// append the changeset
pad.appendRevision(changeset);
// update the clients on the pad
padMessageHandler.updatePadClients(pad);
await Promise.all([
pad.appendRevision(changeset),
padMessageHandler.updatePadClients(pad),
]);
}
/**
@ -688,7 +685,7 @@ exports.setPublicStatus = async function(padID, publicStatus)
}
// set the password
pad.setPublicStatus(publicStatus);
await pad.setPublicStatus(publicStatus);
}
/**
@ -726,7 +723,7 @@ exports.setPassword = async function(padID, password)
let pad = await getPadSafe(padID, true);
// set the password
pad.setPassword(password == "" ? null : password);
await pad.setPassword(password === '' ? null : password);
}
/**

View file

@ -245,6 +245,6 @@ exports.removePad = async function(authorID, padID)
if (author.padIDs !== null) {
// remove pad from author
delete author.padIDs[padID];
db.set("globalAuthor:" + authorID, author);
await db.set('globalAuthor:' + authorID, author);
}
}

View file

@ -71,7 +71,7 @@ Pad.prototype.getPublicStatus = function getPublicStatus() {
return this.publicStatus;
};
Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
Pad.prototype.appendRevision = async function appendRevision(aChangeset, author) {
if (!author) {
author = '';
}
@ -97,12 +97,14 @@ Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
newRevData.meta.atext = this.atext;
}
db.set("pad:" + this.id + ":revs:" + newRev, newRevData);
this.saveToDatabase();
const p = [
db.set('pad:' + this.id + ':revs:' + newRev, newRevData),
this.saveToDatabase(),
];
// set the author to pad
if (author) {
authorManager.addPad(author, this.id);
p.push(authorManager.addPad(author, this.id));
}
if (this.head == 0) {
@ -110,10 +112,12 @@ Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
} else {
hooks.callAll("padUpdate", {'pad':this, 'author': author});
}
await Promise.all(p);
};
// save all attributes to the database
Pad.prototype.saveToDatabase = function saveToDatabase() {
Pad.prototype.saveToDatabase = async function saveToDatabase() {
var dbObject = {};
for (var attr in this) {
@ -127,7 +131,7 @@ Pad.prototype.saveToDatabase = function saveToDatabase() {
}
}
db.set("pad:" + this.id, dbObject);
await db.set('pad:' + this.id, dbObject);
}
// get time of last edit (changeset application)
@ -244,7 +248,7 @@ Pad.prototype.text = function text() {
return this.atext.text;
};
Pad.prototype.setText = function setText(newText) {
Pad.prototype.setText = async function setText(newText) {
// clean the new text
newText = exports.cleanText(newText);
@ -261,10 +265,10 @@ Pad.prototype.setText = function setText(newText) {
}
// append the changeset
this.appendRevision(changeset);
await this.appendRevision(changeset);
};
Pad.prototype.appendText = function appendText(newText) {
Pad.prototype.appendText = async function appendText(newText) {
// clean the new text
newText = exports.cleanText(newText);
@ -274,14 +278,16 @@ Pad.prototype.appendText = function appendText(newText) {
var changeset = Changeset.makeSplice(oldText, oldText.length, 0, newText);
// append the changeset
this.appendRevision(changeset);
await this.appendRevision(changeset);
};
Pad.prototype.appendChatMessage = function appendChatMessage(text, userId, time) {
Pad.prototype.appendChatMessage = async function appendChatMessage(text, userId, time) {
this.chatHead++;
// save the chat entry in the database
db.set("pad:" + this.id + ":chat:" + this.chatHead, { "text": text, "userId": userId, "time": time });
this.saveToDatabase();
await Promise.all([
db.set('pad:' + this.id + ':chat:' + this.chatHead, {text, userId, time}),
this.saveToDatabase(),
]);
};
Pad.prototype.getChatMessage = async function getChatMessage(entryNum) {
@ -350,7 +356,7 @@ Pad.prototype.init = async function init(text) {
// this pad doesn't exist, so create it
let firstChangeset = Changeset.makeSplice("\n", 0, 0, exports.cleanText(text));
this.appendRevision(firstChangeset, '');
await this.appendRevision(firstChangeset, '');
}
hooks.callAll("padLoad", { 'pad': this });
@ -366,7 +372,7 @@ Pad.prototype.copy = async function copy(destinationID, force) {
// padMessageHandler.kickSessionsFromPad(sourceID);
// flush the source pad:
this.saveToDatabase();
await this.saveToDatabase();
try {
@ -532,6 +538,7 @@ Pad.prototype.copyPadWithoutHistory = async function copyPadWithoutHistory(desti
Pad.prototype.remove = async function remove() {
var padID = this.id;
const p = [];
// kick everyone from this pad
padMessageHandler.kickSessionsFromPad(padID);
@ -552,44 +559,45 @@ Pad.prototype.remove = async function remove() {
delete group.pads[padID];
// set the new value
db.set("group:" + groupID, group);
p.push(db.set('group:' + groupID, group));
}
// remove the readonly entries
let readonlyID = readOnlyManager.getReadOnlyId(padID);
db.remove("pad2readonly:" + padID);
db.remove("readonly2pad:" + readonlyID);
p.push(readOnlyManager.getReadOnlyId(padID).then(async (readonlyID) => {
await db.remove('readonly2pad:' + readonlyID);
}));
p.push(db.remove('pad2readonly:' + padID));
// delete all chat messages
promises.timesLimit(this.chatHead + 1, 500, function (i) {
return db.remove("pad:" + padID + ":chat:" + i, null);
})
p.push(promises.timesLimit(this.chatHead + 1, 500, async (i) => {
await db.remove('pad:' + padID + ':chat:' + i, null);
}));
// delete all revisions
promises.timesLimit(this.head + 1, 500, function (i) {
return db.remove("pad:" + padID + ":revs:" + i, null);
})
p.push(promises.timesLimit(this.head + 1, 500, async (i) => {
await db.remove('pad:' + padID + ':revs:' + i, null);
}));
// remove pad from all authors who contributed
this.getAllAuthors().forEach(authorID => {
authorManager.removePad(authorID, padID);
p.push(authorManager.removePad(authorID, padID));
});
// delete the pad entry and delete pad from padManager
padManager.removePad(padID);
p.push(padManager.removePad(padID));
hooks.callAll("padRemove", { padID });
await Promise.all(p);
}
// set in db
Pad.prototype.setPublicStatus = function setPublicStatus(publicStatus) {
Pad.prototype.setPublicStatus = async function setPublicStatus(publicStatus) {
this.publicStatus = publicStatus;
this.saveToDatabase();
await this.saveToDatabase();
};
Pad.prototype.setPassword = function setPassword(password) {
Pad.prototype.setPassword = async function setPassword(password) {
this.passwordHash = password == null ? null : hash(password, generateSalt());
this.saveToDatabase();
await this.saveToDatabase();
};
Pad.prototype.isCorrectPassword = function isCorrectPassword(password) {
@ -600,7 +608,7 @@ Pad.prototype.isPasswordProtected = function isPasswordProtected() {
return this.passwordHash != null;
};
Pad.prototype.addSavedRevision = function addSavedRevision(revNum, savedById, label) {
Pad.prototype.addSavedRevision = async function addSavedRevision(revNum, savedById, label) {
// if this revision is already saved, return silently
for (var i in this.savedRevisions) {
if (this.savedRevisions[i] && this.savedRevisions[i].revNum === revNum) {
@ -618,7 +626,7 @@ Pad.prototype.addSavedRevision = function addSavedRevision(revNum, savedById, la
// save this new saved revision
this.savedRevisions.push(savedRevision);
this.saveToDatabase();
await this.saveToDatabase();
};
Pad.prototype.getSavedRevisions = function getSavedRevisions() {

View file

@ -200,10 +200,11 @@ exports.isValidPadId = function(padId)
/**
* Removes the pad from database and unloads it.
*/
exports.removePad = function(padId) {
db.remove("pad:" + padId);
exports.removePad = async (padId) => {
const p = db.remove('pad:' + padId);
exports.unloadPad(padId);
padList.removePad(padId);
await p;
}
// removes a pad from the cache