Migrate dmpWorker to TypeScript

Signed-off-by: Yannick Bungers <git@innay.de>
Signed-off-by: David Mehren <dmehren1@gmail.com>
This commit is contained in:
Yannick Bungers 2020-04-12 20:40:07 +02:00 committed by David Mehren
parent 41726949e8
commit 8ed198ffcb
No known key found for this signature in database
GPG key ID: 6017AF117F9756CB
2 changed files with 156 additions and 133 deletions

View file

@ -1,133 +0,0 @@
'use strict'
// external modules
var DiffMatchPatch = require('diff-match-patch')
var dmp = new DiffMatchPatch()
// core
var logger = require('../logger')
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 msStart = (new Date()).getTime()
var diff = dmp.diff_main(lastDoc, currDoc)
var patch = dmp.patch_make(lastDoc, diff)
patch = dmp.patch_toText(patch)
var msEnd = (new Date()).getTime()
logger.debug(patch)
logger.debug((msEnd - msStart) + 'ms')
return patch
}
function getRevision (revisions, count) {
var msStart = (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 (let i = 0; i < count; i++) {
let revision = revisions[i]
if (i === 0) {
startContent = revision.content || revision.lastContent
}
if (i !== count - 1) {
let patch = dmp.patch_fromText(revision.patch)
applyPatches = applyPatches.concat(patch)
}
lastPatch = revision.patch
authorship = revision.authorship
}
// 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++) {
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--) {
let revision = revisions[i]
if (i === l) {
startContent = revision.lastContent
authorship = revision.authorship
}
if (revision.patch) {
let patch = dmp.patch_fromText(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(lastPatch),
authorship: authorship
}
var msEnd = (new Date()).getTime()
logger.debug((msEnd - msStart) + '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)
})

156
lib/workers/dmpWorker.ts Normal file
View file

@ -0,0 +1,156 @@
// external modules
// eslint-disable-next-line @typescript-eslint/camelcase
import { diff_match_patch, patch_obj, DIFF_INSERT, DIFF_DELETE } from 'diff-match-patch'
import { logger } from '../logger'
import { Revision } from '../models'
import * as process from 'process'
// Function for suppressing TS2722
// eslint-disable-next-line @typescript-eslint/unbound-method,@typescript-eslint/no-empty-function
const send = process.send || function (): boolean {
return false
}
// eslint-disable-next-line @typescript-eslint/camelcase,new-cap
const dmp: diff_match_patch = new diff_match_patch()
// eslint-disable-next-line @typescript-eslint/camelcase
function getRevision (revisions: Revision[], count: number): {content: string; patch: patch_obj[]; authorship: string} {
const msStart = (new Date()).getTime()
let startContent = ''
let lastPatch = ''
// eslint-disable-next-line @typescript-eslint/camelcase
let applyPatches: patch_obj[] = []
let authorship = ''
if (count <= Math.round(revisions.length / 2)) {
// start from top to target
for (let i = 0; i < count; i++) {
const revision = revisions[i]
if (i === 0) {
startContent = revision.content || revision.lastContent
}
if (i !== count - 1) {
// eslint-disable-next-line @typescript-eslint/camelcase
const patch: patch_obj[] = dmp.patch_fromText(revision.patch)
applyPatches = applyPatches.concat(patch)
}
lastPatch = revision.patch
authorship = revision.authorship
}
// 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++) {
const diff = applyPatches[i].diffs[j]
if (diff[0] === DIFF_INSERT) { diff[0] = DIFF_DELETE } else if (diff[0] === DIFF_DELETE) { diff[0] = DIFF_INSERT }
}
}
} else {
// start from bottom to target
const l = revisions.length - 1
for (let i = l; i >= count - 1; i--) {
const revision = revisions[i]
if (i === l) {
startContent = revision.lastContent
authorship = revision.authorship
}
if (revision.patch) {
// eslint-disable-next-line @typescript-eslint/camelcase
const patch: patch_obj[] = dmp.patch_fromText(revision.patch)
applyPatches = applyPatches.concat(patch)
}
lastPatch = revision.patch
authorship = revision.authorship
}
}
let finalContent = ''
try {
finalContent = dmp.patch_apply(applyPatches, startContent)[0]
} catch (err) {
throw new Error(err)
}
const data = {
content: finalContent,
patch: dmp.patch_fromText(lastPatch),
authorship: authorship
}
const msEnd = (new Date()).getTime()
logger.debug((msEnd - msStart) + 'ms')
return data
}
function createPatch (lastDoc: string, currDoc: string): string {
const msStart = (new Date()).getTime()
const diff = dmp.diff_main(lastDoc, currDoc)
// eslint-disable-next-line @typescript-eslint/camelcase
const patch: patch_obj[] = dmp.patch_make(lastDoc, diff)
const strPatch: string = dmp.patch_toText(patch)
const msEnd = (new Date()).getTime()
logger.debug(strPatch)
logger.debug((msEnd - msStart) + 'ms')
return strPatch
}
class Data {
msg: string;
cacheKey: any;
lastDoc?: string;
currDoc?: string;
revisions?: Revision[];
count?: number;
}
process.on('message', function (data: Data) {
if (!data || !data.msg || !data.cacheKey) {
return logger.error('dmp worker error: not enough data')
}
switch (data.msg) {
case 'create patch':
if (!data.lastDoc || !data.currDoc) {
return logger.error('dmp worker error: not enough data on create patch')
}
try {
const patch: string = createPatch(data.lastDoc, data.currDoc)
send({
msg: 'check',
result: patch,
cacheKey: data.cacheKey
})
} catch (err) {
logger.error('dmp worker error', err)
send({
msg: 'error',
error: err,
cacheKey: data.cacheKey
})
}
break
case 'get revision':
if (!data.revisions || !data.count) {
return logger.error('dmp worker error: not enough data on get revision')
}
try {
// eslint-disable-next-line @typescript-eslint/camelcase
const result: {content: string; patch: patch_obj[]; authorship: string} = getRevision(data.revisions, data.count)
send({
msg: 'check',
result: result,
cacheKey: data.cacheKey
})
} catch (err) {
logger.error('dmp worker error', err)
send({
msg: 'error',
error: err,
cacheKey: data.cacheKey
})
}
break
}
})
// log uncaught exception
process.on('uncaughtException', function (err: Error) {
logger.error('An uncaught exception has occured.')
logger.error(err)
logger.error('Process will exit now.')
process.exit(1)
})