diff options
Diffstat (limited to 'lib/workers')
-rw-r--r-- | lib/workers/dmpWorker.js | 142 | ||||
-rw-r--r-- | lib/workers/historyUpdater.js | 66 | ||||
-rw-r--r-- | lib/workers/noteRevisionSaver.js | 19 | ||||
-rw-r--r-- | lib/workers/noteUpdater.js | 101 |
4 files changed, 142 insertions, 186 deletions
diff --git a/lib/workers/dmpWorker.js b/lib/workers/dmpWorker.js new file mode 100644 index 00000000..fae36191 --- /dev/null +++ b/lib/workers/dmpWorker.js @@ -0,0 +1,142 @@ +// external modules +var LZString = require('lz-string'); +var DiffMatchPatch = require('diff-match-patch'); +var dmp = new DiffMatchPatch(); + +// core +var config = require("../config.js"); +var logger = require("../logger.js"); + +process.on('message', function(data) { + if (!data || !data.msg || !data.cacheKey) { + return logger.error('dmp worker error: not enough data'); + } + switch (data.msg) { + case 'create patch': + if (!data.hasOwnProperty('lastDoc') || !data.hasOwnProperty('currDoc')) { + return logger.error('dmp worker error: not enough data on create patch'); + } + try { + var patch = createPatch(data.lastDoc, data.currDoc); + process.send({ + msg: 'check', + result: patch, + cacheKey: data.cacheKey + }); + } catch (err) { + logger.error('dmp worker error', err); + process.send({ + msg: 'error', + error: err, + cacheKey: data.cacheKey + }); + } + break; + case 'get revision': + if (!data.hasOwnProperty('revisions') || !data.hasOwnProperty('count')) { + return logger.error('dmp worker error: not enough data on get revision'); + } + try { + var result = getRevision(data.revisions, data.count); + process.send({ + msg: 'check', + result: result, + cacheKey: data.cacheKey + }); + } catch (err) { + logger.error('dmp worker error', err); + process.send({ + msg: 'error', + error: err, + cacheKey: data.cacheKey + }); + } + break; + } +}); + +function createPatch(lastDoc, currDoc) { + var ms_start = (new Date()).getTime(); + var diff = dmp.diff_main(lastDoc, currDoc); + dmp.diff_cleanupSemantic(diff); + var patch = dmp.patch_make(lastDoc, diff); + patch = dmp.patch_toText(patch); + var ms_end = (new Date()).getTime(); + if (config.debug) { + logger.info(patch); + logger.info((ms_end - ms_start) + 'ms'); + } + return patch; +} + +function getRevision(revisions, count) { + var ms_start = (new Date()).getTime(); + var startContent = null; + var lastPatch = []; + var applyPatches = []; + var authorship = []; + if (count <= Math.round(revisions.length / 2)) { + // start from top to target + for (var i = 0; i < count; i++) { + var revision = revisions[i]; + if (i == 0) { + startContent = LZString.decompressFromBase64(revision.content || revision.lastContent); + } + if (i != count - 1) { + var patch = dmp.patch_fromText(LZString.decompressFromBase64(revision.patch)); + applyPatches = applyPatches.concat(patch); + } + lastPatch = revision.patch; + authorship = revision.authorship; + } + // swap DIFF_INSERT and DIFF_DELETE to achieve unpatching + for (var i = 0, l = applyPatches.length; i < l; i++) { + for (var j = 0, m = applyPatches[i].diffs.length; j < m; j++) { + var diff = applyPatches[i].diffs[j]; + if (diff[0] == DiffMatchPatch.DIFF_INSERT) + diff[0] = DiffMatchPatch.DIFF_DELETE; + else if (diff[0] == DiffMatchPatch.DIFF_DELETE) + diff[0] = DiffMatchPatch.DIFF_INSERT; + } + } + } else { + // start from bottom to target + var l = revisions.length - 1; + for (var i = l; i >= count - 1; i--) { + var revision = revisions[i]; + if (i == l) { + startContent = LZString.decompressFromBase64(revision.lastContent); + authorship = revision.authorship; + } + if (revision.patch) { + var patch = dmp.patch_fromText(LZString.decompressFromBase64(revision.patch)); + applyPatches = applyPatches.concat(patch); + } + lastPatch = revision.patch; + authorship = revision.authorship; + } + } + try { + var finalContent = dmp.patch_apply(applyPatches, startContent)[0]; + } catch (err) { + throw new Error(err); + } + var data = { + content: finalContent, + patch: dmp.patch_fromText(LZString.decompressFromBase64(lastPatch)), + authorship: authorship ? JSON.parse(LZString.decompressFromBase64(authorship)) : null + }; + var ms_end = (new Date()).getTime(); + if (config.debug) { + logger.info((ms_end - ms_start) + 'ms'); + } + return data; +} + +// log uncaught exception +process.on('uncaughtException', function (err) { + logger.error('An uncaught exception has occured.'); + logger.error(err); + logger.error('Process will exit now.'); + process.exit(1); +});
\ No newline at end of file diff --git a/lib/workers/historyUpdater.js b/lib/workers/historyUpdater.js deleted file mode 100644 index df80e92d..00000000 --- a/lib/workers/historyUpdater.js +++ /dev/null @@ -1,66 +0,0 @@ -// external modules -var async = require('async'); - -// core -var config = require("../config.js"); -var logger = require("../logger.js"); -var models = require("../models"); - -process.on('message', function (data) { - if (!data || !data.msg || data.msg !== 'update history' || !data.caches) return process.exit(); - var caches = data.caches; - async.each(Object.keys(caches), function (key, callback) { - var cache = caches[key]; - if (config.debug) logger.info("history updater found dirty history: " + key); - var history = parseHistoryToArray(cache); - finishUpdateHistory(key, history, function (err, count) { - if (err) return callback(err, null); - if (!count) return callback(null, null); - process.send({ - msg: 'check', - userid: key - }); - return callback(null, null); - }); - }, function (err) { - if (err) logger.error('history updater error', err); - process.exit(); - }); -}); - -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 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; -} - -module.exports = { - parseHistoryToArray: parseHistoryToArray, - parseHistoryToObject: parseHistoryToObject -};
\ No newline at end of file diff --git a/lib/workers/noteRevisionSaver.js b/lib/workers/noteRevisionSaver.js deleted file mode 100644 index b6b117a3..00000000 --- a/lib/workers/noteRevisionSaver.js +++ /dev/null @@ -1,19 +0,0 @@ -// core -var logger = require("../logger.js"); -var models = require("../models"); - -process.on('message', function (data) { - if (!data || !data.msg || data.msg !== 'save note revision') return process.exit(); - models.Revision.saveAllNotesRevision(function (err, notes) { - if (err) { - logger.error('note revision saver failed: ' + err); - return process.exit(); - } - if (notes && notes.length <= 0) { - process.send({ - msg: 'empty' - }); - } - process.exit(); - }); -});
\ No newline at end of file diff --git a/lib/workers/noteUpdater.js b/lib/workers/noteUpdater.js deleted file mode 100644 index 3fc4b1eb..00000000 --- a/lib/workers/noteUpdater.js +++ /dev/null @@ -1,101 +0,0 @@ -// external modules -var async = require('async'); -var moment = require('moment'); -var LZString = require('lz-string'); - -// core -var config = require("../config.js"); -var logger = require("../logger.js"); -var models = require("../models"); - -process.on('message', function (data) { - if (!data || !data.msg || data.msg !== 'update note' || !data.notes) return process.exit(); - var notes = data.notes; - async.each(Object.keys(notes), function (key, callback) { - var note = notes[key]; - if (config.debug) logger.info("note updater found dirty note: " + key); - updateNote(note, function(err, _note) { - if (!_note) { - process.send({ - msg: 'note not found', - note: note - }); - logger.error('note not found: ', note.id); - } - if (err || !_note) { - process.send({ - msg: 'error', - note: note - }); - return callback(err, null); - } - note.updatetime = moment(_note.lastchangeAt).valueOf(); - process.send({ - msg: 'check', - note: note - }); - return callback(null, null); - }); - }, function (err) { - if (err) logger.error('note updater error', err); - process.exit(); - }); -}); - -function updateNote(note, callback) { - models.Note.findOne({ - where: { - id: note.id - } - }).then(function (_note) { - if (!_note) return callback(null, null); - if (note.lastchangeuser) { - if (_note.lastchangeuserId != note.lastchangeuser) { - models.User.findOne({ - where: { - id: note.lastchangeuser - } - }).then(function (user) { - if (!user) return callback(null, null); - note.lastchangeuserprofile = models.User.parseProfile(user.profile); - return finishUpdateNote(note, _note, callback); - }).catch(function (err) { - logger.error(err); - return callback(err, null); - }); - } else { - return finishUpdateNote(note, _note, callback); - } - } else { - note.lastchangeuserprofile = null; - return finishUpdateNote(note, _note, callback); - } - }).catch(function (err) { - logger.error(err); - return callback(err, null); - }); -} - -function finishUpdateNote(note, _note, callback) { - var body = note.document; - var title = note.title = models.Note.parseNoteTitle(body); - title = LZString.compressToBase64(title); - body = LZString.compressToBase64(body); - var values = { - title: title, - content: body, - authorship: LZString.compressToBase64(JSON.stringify(note.authorship)), - lastchangeuserId: note.lastchangeuser, - lastchangeAt: Date.now() - }; - _note.update(values).then(function (_note) { - return callback(null, _note); - }).catch(function (err) { - logger.error(err); - return callback(err, null); - }); -} - -module.exports = { - updateNote: updateNote -};
\ No newline at end of file |