225 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			225 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
//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);
 | 
						|
            cache.isDirty = false;
 | 
						|
            finishUpdateHistory(key, history, function (err, count) {
 | 
						|
                if (err) return callback(err, null);
 | 
						|
                if (!count) return callback(null, null);
 | 
						|
                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) {
 | 
						|
    if (userid && noteId && typeof document !== 'undefined') {
 | 
						|
        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().valueOf();
 | 
						|
            noteHistory.tags = noteInfo.tags;
 | 
						|
            caches[userid].isDirty = true;
 | 
						|
        });
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
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; |