mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-22 09:46:30 -05:00
Update to add cache to history
This commit is contained in:
parent
dc343978eb
commit
af77bb8f59
2 changed files with 233 additions and 51 deletions
56
app.js
56
app.js
|
@ -22,6 +22,7 @@ var i18n = require('i18n');
|
|||
var config = require("./lib/config.js");
|
||||
var logger = require("./lib/logger.js");
|
||||
var auth = require("./lib/auth.js");
|
||||
var history = require("./lib/history.js");
|
||||
var response = require("./lib/response.js");
|
||||
var models = require("./lib/models");
|
||||
|
||||
|
@ -365,56 +366,9 @@ app.get('/logout', function (req, res) {
|
|||
res.redirect(config.serverurl + '/');
|
||||
});
|
||||
//get history
|
||||
app.get('/history', function (req, res) {
|
||||
if (req.isAuthenticated()) {
|
||||
models.User.findOne({
|
||||
where: {
|
||||
id: req.user.id
|
||||
}
|
||||
}).then(function (user) {
|
||||
if (!user)
|
||||
return response.errorNotFound(res);
|
||||
var history = [];
|
||||
if (user.history)
|
||||
history = JSON.parse(user.history);
|
||||
res.send({
|
||||
history: history
|
||||
});
|
||||
if (config.debug)
|
||||
logger.info('read history success: ' + user.id);
|
||||
}).catch(function (err) {
|
||||
logger.error('read history failed: ' + err);
|
||||
return response.errorInternalError(res);
|
||||
});
|
||||
} else {
|
||||
return response.errorForbidden(res);
|
||||
}
|
||||
});
|
||||
app.get('/history', history.historyGet);
|
||||
//post history
|
||||
app.post('/history', urlencodedParser, function (req, res) {
|
||||
if (req.isAuthenticated()) {
|
||||
if (config.debug)
|
||||
logger.info('SERVER received history from [' + req.user.id + ']: ' + req.body.history);
|
||||
models.User.update({
|
||||
history: req.body.history
|
||||
}, {
|
||||
where: {
|
||||
id: req.user.id
|
||||
}
|
||||
}).then(function (count) {
|
||||
if (!count)
|
||||
return response.errorNotFound(res);
|
||||
if (config.debug)
|
||||
logger.info("write user history success: " + req.user.id);
|
||||
}).catch(function (err) {
|
||||
logger.error('write history failed: ' + err);
|
||||
return response.errorInternalError(res);
|
||||
});
|
||||
res.end();
|
||||
} else {
|
||||
return response.errorForbidden(res);
|
||||
}
|
||||
});
|
||||
app.post('/history', urlencodedParser, history.historyPost);
|
||||
//get me info
|
||||
app.get('/me', function (req, res) {
|
||||
if (req.isAuthenticated()) {
|
||||
|
@ -522,7 +476,7 @@ function startListen() {
|
|||
// sync db then start listen
|
||||
models.sequelize.sync().then(function () {
|
||||
// check if realtime is ready
|
||||
if (realtime.isReady()) {
|
||||
if (history.isReady() && realtime.isReady()) {
|
||||
models.Revision.checkAllNotesRevision(function (err, notes) {
|
||||
if (err) return new Error(err);
|
||||
if (!notes || notes.length <= 0) return startListen();
|
||||
|
@ -549,7 +503,7 @@ process.on('SIGINT', function () {
|
|||
socket.disconnect(true);
|
||||
});
|
||||
var checkCleanTimer = setInterval(function () {
|
||||
if (realtime.isReady()) {
|
||||
if (history.isReady() && realtime.isReady()) {
|
||||
models.Revision.checkAllNotesRevision(function (err, notes) {
|
||||
if (err) return new Error(err);
|
||||
if (notes.length <= 0) {
|
||||
|
|
228
lib/history.js
Normal file
228
lib/history.js
Normal file
|
@ -0,0 +1,228 @@
|
|||
//history
|
||||
//external modules
|
||||
var async = require('async');
|
||||
var moment = require('moment');
|
||||
|
||||
//core
|
||||
var config = require("./config.js");
|
||||
var logger = require("./logger.js");
|
||||
var response = require("./response.js");
|
||||
var models = require("./models");
|
||||
|
||||
//public
|
||||
var History = {
|
||||
historyGet: historyGet,
|
||||
historyPost: historyPost,
|
||||
historyDelete: historyDelete,
|
||||
isReady: isReady,
|
||||
updateHistory: updateHistory
|
||||
};
|
||||
|
||||
var caches = {};
|
||||
//update when the history is dirty
|
||||
var updater = setInterval(function () {
|
||||
var deleted = [];
|
||||
async.each(Object.keys(caches), function (key, callback) {
|
||||
var cache = caches[key];
|
||||
if (cache.isDirty) {
|
||||
if (config.debug) logger.info("history updater found dirty history: " + key);
|
||||
var history = parseHistoryToArray(cache.history);
|
||||
finishUpdateHistory(key, history, function (err, count) {
|
||||
if (err) return callback(err, null);
|
||||
if (!count) return callback(null, null);
|
||||
cache.isDirty = false;
|
||||
cache.updateAt = Date.now();
|
||||
return callback(null, null);
|
||||
});
|
||||
} else {
|
||||
if (moment().isAfter(moment(cache.updateAt).add(5, 'minutes'))) {
|
||||
deleted.push(key);
|
||||
}
|
||||
return callback(null, null);
|
||||
}
|
||||
}, function (err) {
|
||||
if (err) return logger.error('history updater error', err);
|
||||
});
|
||||
// delete specified caches
|
||||
for (var i = 0, l = deleted.length; i < l; i++) {
|
||||
caches[deleted[i]].history = {};
|
||||
delete caches[deleted[i]];
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
function finishUpdateHistory(userid, history, callback) {
|
||||
models.User.update({
|
||||
history: JSON.stringify(history)
|
||||
}, {
|
||||
where: {
|
||||
id: userid
|
||||
}
|
||||
}).then(function (count) {
|
||||
return callback(null, count);
|
||||
}).catch(function (err) {
|
||||
return callback(err, null);
|
||||
});
|
||||
}
|
||||
|
||||
function isReady() {
|
||||
var dirtyCount = 0;
|
||||
async.each(Object.keys(caches), function (key, callback) {
|
||||
if (caches[key].isDirty) dirtyCount++;
|
||||
return callback(null, null);
|
||||
}, function (err) {
|
||||
if (err) return logger.error('history ready check error', err);
|
||||
});
|
||||
return dirtyCount > 0 ? false : true;
|
||||
}
|
||||
|
||||
function getHistory(userid, callback) {
|
||||
if (caches[userid]) {
|
||||
return callback(null, caches[userid].history);
|
||||
} else {
|
||||
models.User.findOne({
|
||||
where: {
|
||||
id: userid
|
||||
}
|
||||
}).then(function (user) {
|
||||
if (!user)
|
||||
return callback(null, null);
|
||||
var history = [];
|
||||
if (user.history)
|
||||
history = JSON.parse(user.history);
|
||||
if (config.debug)
|
||||
logger.info('read history success: ' + user.id);
|
||||
setHistory(userid, history);
|
||||
return callback(null, history);
|
||||
}).catch(function (err) {
|
||||
logger.error('read history failed: ' + err);
|
||||
return callback(err, null);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function setHistory(userid, history) {
|
||||
if (Array.isArray(history)) history = parseHistoryToObject(history);
|
||||
if (!caches[userid]) {
|
||||
caches[userid] = {
|
||||
history: {},
|
||||
isDirty: false,
|
||||
updateAt: Date.now()
|
||||
};
|
||||
}
|
||||
caches[userid].history = history;
|
||||
}
|
||||
|
||||
function updateHistory(userid, noteId, document) {
|
||||
var t0 = new Date().getTime();
|
||||
if (userid && noteId && document) {
|
||||
getHistory(userid, function (err, history) {
|
||||
if (err || !history) return;
|
||||
if (!caches[userid].history[noteId]) {
|
||||
caches[userid].history[noteId] = {};
|
||||
}
|
||||
var noteHistory = caches[userid].history[noteId];
|
||||
var noteInfo = models.Note.parseNoteInfo(document);
|
||||
noteHistory.id = noteId;
|
||||
noteHistory.text = noteInfo.title;
|
||||
noteHistory.time = moment().format('MMMM Do YYYY, h:mm:ss a');
|
||||
noteHistory.tags = noteInfo.tags;
|
||||
caches[userid].isDirty = true;
|
||||
var t1 = new Date().getTime();
|
||||
console.warn(t1 - t0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function parseHistoryToArray(history) {
|
||||
var _history = [];
|
||||
Object.keys(history).forEach(function (key) {
|
||||
var item = history[key];
|
||||
_history.push(item);
|
||||
});
|
||||
return _history;
|
||||
}
|
||||
|
||||
function parseHistoryToObject(history) {
|
||||
var _history = {};
|
||||
for (var i = 0, l = history.length; i < l; i++) {
|
||||
var item = history[i];
|
||||
_history[item.id] = item;
|
||||
}
|
||||
return _history;
|
||||
}
|
||||
|
||||
function historyGet(req, res) {
|
||||
if (req.isAuthenticated()) {
|
||||
getHistory(req.user.id, function (err, history) {
|
||||
if (err) return response.errorInternalError(res);
|
||||
if (!history) return response.errorNotFound(res);
|
||||
res.send({
|
||||
history: parseHistoryToArray(history)
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return response.errorForbidden(res);
|
||||
}
|
||||
}
|
||||
|
||||
function historyPost(req, res) {
|
||||
if (req.isAuthenticated()) {
|
||||
var noteId = req.params.noteId;
|
||||
if (!noteId) {
|
||||
if (typeof req.body['history'] === 'undefined') return response.errorBadRequest(res);
|
||||
if (config.debug)
|
||||
logger.info('SERVER received history from [' + req.user.id + ']: ' + req.body.history);
|
||||
try {
|
||||
var history = JSON.parse(req.body.history);
|
||||
} catch (err) {
|
||||
return response.errorBadRequest(res);
|
||||
}
|
||||
if (Array.isArray(history)) {
|
||||
setHistory(req.user.id, history);
|
||||
caches[req.user.id].isDirty = true;
|
||||
res.end();
|
||||
} else {
|
||||
return response.errorBadRequest(res);
|
||||
}
|
||||
} else {
|
||||
if (typeof req.body['pinned'] === 'undefined') return response.errorBadRequest(res);
|
||||
getHistory(req.user.id, function (err, history) {
|
||||
if (err) return response.errorInternalError(res);
|
||||
if (!history) return response.errorNotFound(res);
|
||||
if (!caches[req.user.id].history[noteId]) return response.errorNotFound(res);
|
||||
if (req.body.pinned === 'true' || req.body.pinned === 'false') {
|
||||
caches[req.user.id].history[noteId].pinned = (req.body.pinned === 'true');
|
||||
caches[req.user.id].isDirty = true;
|
||||
res.end();
|
||||
} else {
|
||||
return response.errorBadRequest(res);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return response.errorForbidden(res);
|
||||
}
|
||||
}
|
||||
|
||||
function historyDelete(req, res) {
|
||||
if (req.isAuthenticated()) {
|
||||
var noteId = req.params.noteId;
|
||||
if (!noteId) {
|
||||
setHistory(req.user.id, []);
|
||||
caches[req.user.id].isDirty = true;
|
||||
res.end();
|
||||
} else {
|
||||
getHistory(req.user.id, function (err, history) {
|
||||
if (err) return response.errorInternalError(res);
|
||||
if (!history) return response.errorNotFound(res);
|
||||
delete caches[req.user.id].history[noteId];
|
||||
caches[req.user.id].isDirty = true;
|
||||
res.end();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return response.errorForbidden(res);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = History;
|
Loading…
Reference in a new issue