From 8ed198ffcbe394e72cc832e69f8740070d3ea2a1 Mon Sep 17 00:00:00 2001 From: Yannick Bungers Date: Sun, 12 Apr 2020 20:40:07 +0200 Subject: [PATCH] Migrate dmpWorker to TypeScript Signed-off-by: Yannick Bungers Signed-off-by: David Mehren --- lib/workers/dmpWorker.js | 133 --------------------------------- lib/workers/dmpWorker.ts | 156 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 133 deletions(-) delete mode 100644 lib/workers/dmpWorker.js create mode 100644 lib/workers/dmpWorker.ts diff --git a/lib/workers/dmpWorker.js b/lib/workers/dmpWorker.js deleted file mode 100644 index ca68b4ab6..000000000 --- a/lib/workers/dmpWorker.js +++ /dev/null @@ -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) -}) diff --git a/lib/workers/dmpWorker.ts b/lib/workers/dmpWorker.ts new file mode 100644 index 000000000..5ae64436b --- /dev/null +++ b/lib/workers/dmpWorker.ts @@ -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) +})