db/SessionManager.js: mostly converted to Promises

This commit is contained in:
Ray Bellis 2019-01-25 14:53:24 +00:00
parent 16c4c33f49
commit a875ca6c30

View file

@ -21,115 +21,78 @@
var ERR = require("async-stacktrace"); var ERR = require("async-stacktrace");
var customError = require("../utils/customError"); var customError = require("../utils/customError");
var randomString = require("../utils/randomstring"); var randomString = require("../utils/randomstring");
var db = require("./DB").db; var db = require("./DB");
var async = require("async");
var groupManager = require("./GroupManager"); var groupManager = require("./GroupManager");
var authorManager = require("./AuthorManager"); var authorManager = require("./AuthorManager");
const thenify = require("thenify").withCallback; const thenify = require("thenify").withCallback;
exports.doesSessionExist = thenify(function(sessionID, callback) exports.doesSessionExist = async function(sessionID)
{ {
//check if the database entry of this session exists //check if the database entry of this session exists
db.get("session:" + sessionID, function (err, session) let session = await db.get("session:" + sessionID);
{ return (session !== null);
if(ERR(err, callback)) return; }
callback(null, session != null);
});
});
/** /**
* Creates a new session between an author and a group * Creates a new session between an author and a group
*/ */
exports.createSession = thenify(function(groupID, authorID, validUntil, callback) exports.createSession = async function(groupID, authorID, validUntil)
{ {
var sessionID;
async.series([
// check if the group exists // check if the group exists
function(callback) let groupExists = await groupManager.doesGroupExist(groupID);
{ if (!groupExists) {
groupManager.doesGroupExist(groupID, function(err, exists) throw new customError("groupID does not exist", "apierror");
{
if(ERR(err, callback)) return;
// group does not exist
if (exists == false) {
callback(new customError("groupID does not exist", "apierror"));
} else {
// everything is fine, continue
callback();
} }
});
},
// check if the author exists // check if the author exists
function(callback) let authorExists = await authorManager.doesAuthorExist(authorID);
{ if (!authorExists) {
authorManager.doesAuthorExists(authorID, function(err, exists) throw new customError("authorID does not exist", "apierror");
{
if(ERR(err, callback)) return;
if (exists == false) {
// author does not exist
callback(new customError("authorID does not exist", "apierror"));
} else {
// everything is fine, continue
callback();
}
});
},
// check validUntil and create the session db entry
function(callback)
{
// check if rev is a number
if (typeof validUntil != "number")
{
// try to parse the number
if (isNaN(parseInt(validUntil))) {
callback(new customError("validUntil is not a number", "apierror"));
return;
} }
// try to parse validUntil if it's not a number
if (typeof validUntil !== "number") {
validUntil = parseInt(validUntil); validUntil = parseInt(validUntil);
} }
// check it's a valid number
if (isNaN(validUntil)) {
throw new customError("validUntil is not a number", "apierror");
}
// ensure this is not a negative number // ensure this is not a negative number
if (validUntil < 0) { if (validUntil < 0) {
callback(new customError("validUntil is a negative number", "apierror")); throw new customError("validUntil is a negative number", "apierror");
return;
} }
// ensure this is not a float value // ensure this is not a float value
if (!is_int(validUntil)) { if (!is_int(validUntil)) {
callback(new customError("validUntil is a float value", "apierror")); throw new customError("validUntil is a float value", "apierror");
return;
} }
// check if validUntil is in the future // check if validUntil is in the future
if (Math.floor(Date.now()/1000) > validUntil) { if (validUntil < Math.floor(Date.now() / 1000)) {
callback(new customError("validUntil is in the past", "apierror")); throw new customError("validUntil is in the past", "apierror");
return;
} }
// generate sessionID // generate sessionID
sessionID = "s." + randomString(16); let sessionID = "s." + randomString(16);
// set the session into the database // set the session into the database
db.set("session:" + sessionID, {"groupID": groupID, "authorID": authorID, "validUntil": validUntil}); await db.set("session:" + sessionID, {"groupID": groupID, "authorID": authorID, "validUntil": validUntil});
callback();
},
// set the group2sessions entry
function(callback)
{
// get the entry // get the entry
db.get("group2sessions:" + groupID, function(err, group2sessions) let group2sessions = await db.get("group2sessions:" + groupID);
{
if(ERR(err, callback)) return;
if (group2sessions == null || group2sessions.sessionIDs == null) { /*
* In some cases, the db layer could return "undefined" as well as "null".
* Thus, it is not possible to perform strict null checks on group2sessions.
* In a previous version of this code, a strict check broke session
* management.
*
* See: https://github.com/ether/etherpad-lite/issues/3567#issuecomment-468613960
*/
if (!group2sessions || !group2sessions.sessionIDs) {
// the entry doesn't exist so far, let's create it // the entry doesn't exist so far, let's create it
group2sessions = {sessionIDs : {}}; group2sessions = {sessionIDs : {}};
} }
@ -138,19 +101,10 @@ exports.createSession = thenify(function(groupID, authorID, validUntil, callback
group2sessions.sessionIDs[sessionID] = 1; group2sessions.sessionIDs[sessionID] = 1;
// save the new element back // save the new element back
db.set("group2sessions:" + groupID, group2sessions); await db.set("group2sessions:" + groupID, group2sessions);
callback(); // get the author2sessions entry
}); let author2sessions = await db.get("author2sessions:" + authorID);
},
// set the author2sessions entry
function(callback)
{
// get the entry
db.get("author2sessions:" + authorID, function(err, author2sessions)
{
if(ERR(err, callback)) return;
if (author2sessions == null || author2sessions.sessionIDs == null) { if (author2sessions == null || author2sessions.sessionIDs == null) {
// the entry doesn't exist so far, let's create it // the entry doesn't exist so far, let's create it
@ -161,20 +115,12 @@ exports.createSession = thenify(function(groupID, authorID, validUntil, callback
author2sessions.sessionIDs[sessionID] = 1; author2sessions.sessionIDs[sessionID] = 1;
//save the new element back //save the new element back
db.set("author2sessions:" + authorID, author2sessions); await db.set("author2sessions:" + authorID, author2sessions);
callback(); return { sessionID };
});
} }
], function(err)
{
if(ERR(err, callback)) return;
// return error and sessionID
callback(null, {sessionID: sessionID});
})
});
// @TODO once external dependencies are using Promises
exports.getSessionInfo = thenify(function(sessionID, callback) exports.getSessionInfo = thenify(function(sessionID, callback)
{ {
// check if the database entry of this session exists // check if the database entry of this session exists
@ -195,160 +141,86 @@ exports.getSessionInfo = thenify(function(sessionID, callback)
/** /**
* Deletes a session * Deletes a session
*/ */
exports.deleteSession = thenify(function(sessionID, callback) exports.deleteSession = async function(sessionID)
{ {
var authorID, groupID; // ensure that the session exists
var group2sessions, author2sessions; let session = await db.get("session:" + sessionID);
async.series([
function(callback)
{
// get the session entry
db.get("session:" + sessionID, function (err, session)
{
if(ERR(err, callback)) return;
if (session == null) { if (session == null) {
// session does not exist throw new customError("sessionID does not exist", "apierror");
callback(new customError("sessionID does not exist", "apierror"))
} else {
// everything is fine, use the sessioninfos
authorID = session.authorID;
groupID = session.groupID;
callback();
} }
});
},
// get the group2sessions entry // everything is fine, use the sessioninfos
function(callback) let groupID = session.groupID;
{ let authorID = session.authorID;
db.get("group2sessions:" + groupID, function (err, _group2sessions)
{
if(ERR(err, callback)) return;
group2sessions = _group2sessions;
callback();
});
},
// get the author2sessions entry // get the group2sessions and author2sessions entries
function(callback) let group2sessions = await db.get("group2sessions:" + groupID);
{ let author2sessions = await db.get("author2sessions:" + authorID);
db.get("author2sessions:" + authorID, function (err, _author2sessions)
{
if(ERR(err, callback)) return;
author2sessions = _author2sessions;
callback();
});
},
// remove the values from the database
function(callback)
{
// remove the session // remove the session
db.remove("session:" + sessionID); await db.remove("session:" + sessionID);
// remove session from group2sessions // remove session from group2sessions
if (group2sessions != null) { // Maybe the group was already deleted if (group2sessions != null) { // Maybe the group was already deleted
delete group2sessions.sessionIDs[sessionID]; delete group2sessions.sessionIDs[sessionID];
db.set("group2sessions:" + groupID, group2sessions); await db.set("group2sessions:" + groupID, group2sessions);
} }
// remove session from author2sessions // remove session from author2sessions
if (author2sessions != null) { // Maybe the author was already deleted if (author2sessions != null) { // Maybe the author was already deleted
delete author2sessions.sessionIDs[sessionID]; delete author2sessions.sessionIDs[sessionID];
db.set("author2sessions:" + authorID, author2sessions); await db.set("author2sessions:" + authorID, author2sessions);
}
} }
callback(); exports.listSessionsOfGroup = async function(groupID)
{
// check that the group exists
let exists = await groupManager.doesGroupExist(groupID);
if (!exists) {
throw new customError("groupID does not exist", "apierror");
} }
], function(err)
{
if(ERR(err, callback)) return;
callback();
})
});
exports.listSessionsOfGroup = thenify(function(groupID, callback) let sessions = await listSessionsWithDBKey("group2sessions:" + groupID);
{ return sessions;
groupManager.doesGroupExist(groupID, function(err, exists)
{
if(ERR(err, callback)) return;
if (exists == false) {
// group does not exist
callback(new customError("groupID does not exist", "apierror"));
} else {
// everything is fine, continue
listSessionsWithDBKey("group2sessions:" + groupID, callback);
} }
});
});
exports.listSessionsOfAuthor = thenify(function(authorID, callback) exports.listSessionsOfAuthor = async function(authorID)
{ {
authorManager.doesAuthorExists(authorID, function(err, exists) // check that the author exists
{ let exists = await authorManager.doesAuthorExist(authorID)
if(ERR(err, callback)) return; if (!exists) {
throw new customError("authorID does not exist", "apierror");
if (exists == false) { }
// group does not exist
callback(new customError("authorID does not exist", "apierror")); let sessions = await listSessionsWithDBKey("author2sessions:" + authorID);
} else { return sessions;
// everything is fine, continue
listSessionsWithDBKey("author2sessions:" + authorID, callback);
} }
});
});
// this function is basically the code listSessionsOfAuthor and listSessionsOfGroup has in common // this function is basically the code listSessionsOfAuthor and listSessionsOfGroup has in common
function listSessionsWithDBKey (dbkey, callback) // required to return null rather than an empty object if there are none
{ async function listSessionsWithDBKey(dbkey, callback)
var sessions;
async.series([
function(callback)
{ {
// get the group2sessions entry // get the group2sessions entry
db.get(dbkey, function(err, sessionObject) let sessionObject = await db.get(dbkey);
{ let sessions = sessionObject ? sessionObject.sessionIDs : null;
if(ERR(err, callback)) return;
sessions = sessionObject ? sessionObject.sessionIDs : null;
callback();
});
},
function(callback)
{
// collect all sessionIDs in an arrary
var sessionIDs = [];
for (var i in sessions)
{
sessionIDs.push(i);
}
// iterate through the sessions and get the sessioninfos // iterate through the sessions and get the sessioninfos
async.forEach(sessionIDs, function(sessionID, callback) for (let sessionID in sessions) {
{ try {
exports.getSessionInfo(sessionID, function(err, sessionInfo) let sessionInfo = await exports.getSessionInfo(sessionID);
{ sessions[sessionID] = sessionInfo;
} catch (err) {
if (err == "apierror: sessionID does not exist") { if (err == "apierror: sessionID does not exist") {
console.warn(`Found bad session ${sessionID} in ${dbkey}`); console.warn(`Found bad session ${sessionID} in ${dbkey}`);
} else if(ERR(err, callback)) { sessions[sessionID] = null;
return; } else {
throw err;
}
}
} }
sessions[sessionID] = sessionInfo; return sessions;
callback();
});
}, callback);
}
], function(err)
{
if(ERR(err, callback)) return;
callback(null, sessions);
});
} }
// checks if a number is an int // checks if a number is an int