2017-03-14 01:02:43 -04:00
|
|
|
'use strict'
|
2016-11-17 23:09:58 -05:00
|
|
|
// external modules
|
2021-02-15 03:42:51 -05:00
|
|
|
const DiffMatchPatch = require('diff-match-patch')
|
|
|
|
const dmp = new DiffMatchPatch()
|
2016-11-17 23:09:58 -05:00
|
|
|
|
|
|
|
// core
|
2021-02-15 03:42:51 -05:00
|
|
|
const logger = require('../logger')
|
2016-11-17 23:09:58 -05:00
|
|
|
|
2017-03-08 05:45:51 -05:00
|
|
|
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':
|
2021-02-15 03:42:51 -05:00
|
|
|
if (
|
|
|
|
!Object.prototype.hasOwnProperty.call(data, 'lastDoc') ||
|
|
|
|
!Object.prototype.hasOwnProperty.call(data, 'currDoc')
|
|
|
|
) {
|
|
|
|
return logger.error(
|
|
|
|
'dmp worker error: not enough data on create patch'
|
|
|
|
)
|
2017-03-08 05:45:51 -05:00
|
|
|
}
|
|
|
|
try {
|
2021-02-15 03:42:51 -05:00
|
|
|
const patch = createPatch(data.lastDoc, data.currDoc)
|
2017-03-08 05:45:51 -05:00
|
|
|
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':
|
2021-02-15 03:42:51 -05:00
|
|
|
if (
|
|
|
|
!Object.prototype.hasOwnProperty.call(data, 'revisions') ||
|
|
|
|
!Object.prototype.hasOwnProperty.call(data, 'count')
|
|
|
|
) {
|
|
|
|
return logger.error(
|
|
|
|
'dmp worker error: not enough data on get revision'
|
|
|
|
)
|
2017-03-08 05:45:51 -05:00
|
|
|
}
|
|
|
|
try {
|
2021-02-15 03:42:51 -05:00
|
|
|
const result = getRevision(data.revisions, data.count)
|
2017-03-08 05:45:51 -05:00
|
|
|
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
|
|
|
|
}
|
|
|
|
})
|
2016-11-17 23:09:58 -05:00
|
|
|
|
2017-03-08 05:45:51 -05:00
|
|
|
function createPatch (lastDoc, currDoc) {
|
2021-02-15 03:42:51 -05:00
|
|
|
const msStart = new Date().getTime()
|
|
|
|
const diff = dmp.diff_main(lastDoc, currDoc)
|
|
|
|
let patch = dmp.patch_make(lastDoc, diff)
|
2017-03-08 05:45:51 -05:00
|
|
|
patch = dmp.patch_toText(patch)
|
2021-02-15 03:42:51 -05:00
|
|
|
const msEnd = new Date().getTime()
|
2019-06-08 14:51:24 -04:00
|
|
|
logger.debug(patch)
|
2021-02-15 03:42:51 -05:00
|
|
|
logger.debug(msEnd - msStart + 'ms')
|
2017-03-08 05:45:51 -05:00
|
|
|
return patch
|
2016-11-17 23:09:58 -05:00
|
|
|
}
|
|
|
|
|
2017-03-08 05:45:51 -05:00
|
|
|
function getRevision (revisions, count) {
|
2021-02-15 03:42:51 -05:00
|
|
|
const msStart = new Date().getTime()
|
|
|
|
let startContent = null
|
|
|
|
let lastPatch = []
|
|
|
|
let applyPatches = []
|
|
|
|
let authorship = []
|
2017-03-08 05:45:51 -05:00
|
|
|
if (count <= Math.round(revisions.length / 2)) {
|
|
|
|
// start from top to target
|
|
|
|
for (let i = 0; i < count; i++) {
|
2021-02-15 03:42:51 -05:00
|
|
|
const revision = revisions[i]
|
2017-03-08 05:45:51 -05:00
|
|
|
if (i === 0) {
|
|
|
|
startContent = revision.content || revision.lastContent
|
|
|
|
}
|
|
|
|
if (i !== count - 1) {
|
2021-02-15 03:42:51 -05:00
|
|
|
const patch = dmp.patch_fromText(revision.patch)
|
2017-03-08 05:45:51 -05:00
|
|
|
applyPatches = applyPatches.concat(patch)
|
|
|
|
}
|
|
|
|
lastPatch = revision.patch
|
|
|
|
authorship = revision.authorship
|
2016-11-17 23:09:58 -05:00
|
|
|
}
|
2017-03-08 05:45:51 -05:00
|
|
|
// swap DIFF_INSERT and DIFF_DELETE to achieve unpatching
|
|
|
|
for (let i = 0, l = applyPatches.length; i < l; i++) {
|
|
|
|
for (let j = 0, m = applyPatches[i].diffs.length; j < m; j++) {
|
2021-02-15 03:42:51 -05:00
|
|
|
const 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
|
|
|
|
}
|
2017-03-08 05:45:51 -05:00
|
|
|
}
|
2016-11-17 23:09:58 -05:00
|
|
|
}
|
2017-03-08 05:45:51 -05:00
|
|
|
} else {
|
|
|
|
// start from bottom to target
|
2021-02-15 03:42:51 -05:00
|
|
|
const l = revisions.length - 1
|
|
|
|
for (let i = l; i >= count - 1; i--) {
|
|
|
|
const revision = revisions[i]
|
2017-03-08 05:45:51 -05:00
|
|
|
if (i === l) {
|
|
|
|
startContent = revision.lastContent
|
|
|
|
authorship = revision.authorship
|
|
|
|
}
|
|
|
|
if (revision.patch) {
|
2021-02-15 03:42:51 -05:00
|
|
|
const patch = dmp.patch_fromText(revision.patch)
|
2017-03-08 05:45:51 -05:00
|
|
|
applyPatches = applyPatches.concat(patch)
|
|
|
|
}
|
|
|
|
lastPatch = revision.patch
|
|
|
|
authorship = revision.authorship
|
2016-11-17 23:09:58 -05:00
|
|
|
}
|
2017-03-08 05:45:51 -05:00
|
|
|
}
|
|
|
|
try {
|
2021-02-15 03:42:51 -05:00
|
|
|
const finalContent = dmp.patch_apply(applyPatches, startContent)[0]
|
|
|
|
const data = {
|
|
|
|
content: finalContent,
|
|
|
|
patch: dmp.patch_fromText(lastPatch),
|
|
|
|
authorship: authorship
|
|
|
|
}
|
|
|
|
const msEnd = new Date().getTime()
|
|
|
|
logger.debug(msEnd - msStart + 'ms')
|
|
|
|
return data
|
2017-03-08 05:45:51 -05:00
|
|
|
} catch (err) {
|
|
|
|
throw new Error(err)
|
|
|
|
}
|
2016-11-17 23:09:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// log uncaught exception
|
|
|
|
process.on('uncaughtException', function (err) {
|
2017-03-08 05:45:51 -05:00
|
|
|
logger.error('An uncaught exception has occured.')
|
|
|
|
logger.error(err)
|
|
|
|
logger.error('Process will exit now.')
|
|
|
|
process.exit(1)
|
|
|
|
})
|