From 762ac2bf354e4cc2c4b15f42502da939f5061646 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 9 Aug 2024 16:48:18 -0400
Subject: a bunch more typing fixes.

---
 src/client/views/PropertiesButtons.tsx | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

(limited to 'src/client/views/PropertiesButtons.tsx')

diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index edf6df2b9..f346d4ba8 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -1,5 +1,3 @@
-/* eslint-disable jsx-a11y/no-static-element-interactions */
-/* eslint-disable jsx-a11y/click-events-have-key-events */
 /* eslint-disable react/no-unused-class-component-methods */
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Dropdown, DropdownType, IListItemProps, Toggle, ToggleType, Type } from 'browndash-components';
@@ -18,7 +16,7 @@ import { TfiBarChart } from 'react-icons/tfi';
 import { Doc, Opt } from '../../fields/Doc';
 import { DocData } from '../../fields/DocSymbols';
 import { ScriptField } from '../../fields/ScriptField';
-import { BoolCast, ScriptCast } from '../../fields/Types';
+import { BoolCast, ScriptCast, StrCast } from '../../fields/Types';
 import { ImageField } from '../../fields/URLField';
 import { DocUtils, IsFollowLinkScript } from '../documents/DocUtils';
 import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
@@ -32,7 +30,7 @@ import { OpenWhere } from './nodes/OpenWhere';
 import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 
 @observer
-export class PropertiesButtons extends React.Component<{}, {}> {
+export class PropertiesButtons extends React.Component {
     // eslint-disable-next-line no-use-before-define
     @observable public static Instance: PropertiesButtons;
 
@@ -314,13 +312,6 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     //     );
     // }
 
-    @undoBatch
-    handlePerspectiveChange = (e: any) => {
-        this.selectedDoc && (this.selectedDoc._type_collection = e.target.value);
-        DocumentView.Selected().forEach(docView => {
-            docView.layoutDoc._type_collection = e.target.value;
-        });
-    };
     @computed get onClickVal() {
         const linkButton = IsFollowLinkScript(this.selectedDoc.onClick);
         const followLoc = this.selectedDoc._followLinkLocation;
@@ -452,7 +443,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
         else this.selectedDoc && DocUtils.makeCustomViewClicked(this.selectedDoc, undefined, 'onClick');
     };
 
-    propertyToggleBtn = (label: (on?: any) => string, property: string, tooltip: (on?: any) => string, icon: (on?: any) => any, onClick?: (dv: Opt<DocumentView>, doc: Doc, property: string) => void, useUserDoc?: boolean) => {
+    propertyToggleBtn = (label: (on?: unknown) => string, property: string, tooltip: (on?: unknown) => string, icon: (on?: unknown) => unknown, onClick?: (dv: Opt<DocumentView>, doc: Doc, property: string) => void, useUserDoc?: boolean) => {
         const targetDoc = useUserDoc ? Doc.UserDoc() : this.selectedLayoutDoc;
         const onPropToggle = (dv: Opt<DocumentView>, doc: Doc, prop: string) => {
             (dv?.layoutDoc || doc)[prop] = !(dv?.layoutDoc || doc)[prop];
@@ -463,7 +454,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                 tooltip={tooltip(BoolCast(targetDoc[property]))}
                 text={label(targetDoc?.[property])}
                 color={SettingsManager.userColor}
-                icon={icon(targetDoc?.[property] as any)}
+                icon={icon(targetDoc?.[property]) as string}
                 iconPlacement="left"
                 align="flex-start"
                 fillWidth
@@ -484,7 +475,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
         const isImage = layoutField instanceof ImageField;
         const isMap = this.selectedDoc?.type === DocumentType.MAP;
         const isCollection = this.selectedDoc?.type === DocumentType.COL;
-        const isStacking = [CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.NoteTaking].includes(this.selectedDoc?._type_collection as any);
+        const isStacking = [CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.NoteTaking].includes(StrCast(this.selectedDoc?._type_collection) as CollectionViewType);
         const isFreeForm = this.selectedDoc?._type_collection === CollectionViewType.Freeform;
         const isTree = this.selectedDoc?._type_collection === CollectionViewType.Tree;
         const toggle = (ele: JSX.Element | null, style?: React.CSSProperties) => (
-- 
cgit v1.2.3-70-g09d2


From a958577d4c27b276aa37484e3f895e196138b17c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 1 Sep 2024 12:55:59 -0400
Subject: consolidated image resampling.  fixed importing zipped workspace.

---
 src/client/views/PropertiesButtons.tsx             |  20 ---
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   2 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |   4 +-
 src/client/views/nodes/PDFBox.tsx                  |   4 -
 src/server/ApiManagers/SearchManager.ts            | 200 ---------------------
 src/server/ApiManagers/UploadManager.ts            |  49 ++---
 src/server/DashUploadUtils.ts                      |  74 ++++----
 src/server/index.ts                                |   2 -
 8 files changed, 56 insertions(+), 299 deletions(-)
 delete mode 100644 src/server/ApiManagers/SearchManager.ts

(limited to 'src/client/views/PropertiesButtons.tsx')

diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index f346d4ba8..f96a4a255 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -246,26 +246,6 @@ export class PropertiesButtons extends React.Component {
     //     );
     // }
 
-    // @computed get freezeThumb() {
-    //     return this.propertyToggleBtn(
-    //         'FreezeThumb',
-    //         '_thumb-frozen',
-    //         on => `${on ? 'Freeze' : 'Unfreeze'} thumbnail`,
-    //         on => 'snowflake',
-    //         (dv, doc) => {
-    //             if (doc['thumb-frozen']) doc['thumb-frozen'] = undefined;
-    //             else {
-    //                 document.body.focus(); // so that we can access the clipboard without an error
-    //                 setTimeout(() =>
-    //                     pasteImageBitmap((data_url: any, error: any) => {
-    //                         error && console.log(error);
-    //                         data_url && Utils.convertDataUri(data_url, doc[Id] + '-thumb-frozen', true).then(returnedfilename => (doc['thumb-frozen'] = new ImageField(returnedfilename)));
-    //                     })
-    //                 );
-    //             }
-    //         }
-    //     );
-    // }
     @computed get snapButton() {
         // THESE ARE NOT COMING
         return this.propertyToggleBtn(
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index c4cf8dee7..dbf781e63 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1811,7 +1811,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const contentDiv = this.DocumentView?.().ContentDiv;
         contentDiv &&
             UpdateIcon(
-                this.layoutDoc[Id] + '-icon' + new Date().getTime(),
+                this.layoutDoc[Id] + '_icon_' + new Date().getTime(),
                 contentDiv,
                 NumCast(this.layoutDoc._width),
                 NumCast(this.layoutDoc._height),
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 6cc75aa4b..ccb6bc9be 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -160,8 +160,8 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
                 pasteImageBitmap((data: any, error: any) => {
                     error && console.log(error);
                     data &&
-                        ClientUtils.convertDataUri(data, this._props.Document[Id] + '-thumb-frozen').then(returnedfilename => {
-                            this._props.Document['thumb-frozen'] = new ImageField(returnedfilename);
+                        ClientUtils.convertDataUri(data, this._props.Document[Id] + '_icon_' + new Date().getTime()).then(returnedfilename => {
+                            this._props.Document[DocData].icon = new ImageField(returnedfilename);
                         });
                 })
             );
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index b17275a1e..cb0b0d71f 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -56,10 +56,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     @computed get pdfUrl() {
         return Cast(this.dataDoc[this._props.fieldKey], PdfField);
     }
-    @computed get pdfThumb() {
-        return ImageCast(this.layoutDoc['thumb-frozen'], ImageCast(this.layoutDoc.thumb))?.url;
-    }
-
     constructor(props: FieldViewProps) {
         super(props);
         makeObservable(this);
diff --git a/src/server/ApiManagers/SearchManager.ts b/src/server/ApiManagers/SearchManager.ts
deleted file mode 100644
index 684b49eaf..000000000
--- a/src/server/ApiManagers/SearchManager.ts
+++ /dev/null
@@ -1,200 +0,0 @@
-/* eslint-disable no-use-before-define */
-import { exec } from 'child_process';
-import { cyan, green, red, yellow } from 'colors';
-import { logExecution } from '../ActionUtilities';
-import { Method } from '../RouteManager';
-import RouteSubscriber from '../RouteSubscriber';
-import { Search } from '../Search';
-import { Database } from '../database';
-import ApiManager, { Registration } from './ApiManager';
-
-export class SearchManager extends ApiManager {
-    protected initialize(register: Registration): void {
-        register({
-            method: Method.GET,
-            subscription: new RouteSubscriber('solr').add('action'),
-            secureHandler: async ({ req, res }) => {
-                const { action } = req.params;
-                switch (action) {
-                    case 'start':
-                    case 'stop':
-                        {
-                            const status = req.params.action === 'start';
-                            SolrManager.SetRunning(status);
-                        }
-                        break;
-                    case 'update':
-                        await SolrManager.update();
-                        break;
-                    default:
-                        console.log(yellow(`${action} is an unknown solr operation.`));
-                }
-                res.redirect('/home');
-            },
-        });
-
-        register({
-            method: Method.GET,
-            subscription: '/dashsearch',
-            secureHandler: async ({ req, res }) => {
-                const solrQuery: any = {};
-                ['q', 'fq', 'start', 'rows', 'sort', 'hl.maxAnalyzedChars', 'hl', 'hl.fl'].forEach(key => {
-                    solrQuery[key] = req.query[key];
-                });
-                if (solrQuery.q === undefined) {
-                    res.send([]);
-                    return;
-                }
-                const results = await Search.search(solrQuery);
-                res.send(results);
-            },
-        });
-    }
-}
-
-export namespace SolrManager {
-    export function SetRunning(status: boolean) {
-        const args = status ? 'start' : 'stop -p 8983';
-        console.log(`solr management: trying to ${args}`);
-        exec(`solr ${args}`, { cwd: './solr-8.3.1/bin' }, (error, stdout, stderr) => {
-            if (error) {
-                console.log(red(`solr management error: unable to ${args} server`));
-                console.log(red(error.message));
-            }
-            console.log(cyan(stdout));
-            console.log(yellow(stderr));
-        });
-        if (status) {
-            console.log(cyan('Start script is executing: please allow 15 seconds for solr to start on port 8983.'));
-        }
-    }
-
-    export async function update() {
-        console.log(green('Beginning update...'));
-        await logExecution<void>({
-            startMessage: 'Clearing existing Solr information...',
-            endMessage: 'Solr information successfully cleared',
-            action: Search.clear,
-            color: cyan,
-        });
-        const cursor = await logExecution({
-            startMessage: 'Connecting to and querying for all documents from database...',
-            endMessage: ({ result, error }) => {
-                const success = error === null && result !== undefined;
-                if (!success) {
-                    console.log(red('Unable to connect to the database.'));
-                    process.exit(0);
-                }
-                return 'Connection successful and query complete';
-            },
-            action: () => Database.Instance.query({}),
-            color: yellow,
-        });
-        const updates: any[] = [];
-        let numDocs = 0;
-        function updateDoc(doc: any) {
-            numDocs++;
-            if (numDocs % 50 === 0) {
-                console.log(`Batch of 50 complete, total of ${numDocs}`);
-            }
-            if (doc.__type !== 'Doc') {
-                return;
-            }
-            const { fields } = doc;
-            if (!fields) {
-                return;
-            }
-            const update2: any = { id: doc._id };
-            let dynfield = false;
-            fields.forEach((key: any) => {
-                const value = fields[key];
-                const term = ToSearchTerm(value);
-                if (term !== undefined) {
-                    const { suffix, value: tvalue } = term;
-                    if (key.endsWith('modificationDate')) {
-                        update2['modificationDate' + suffix] = tvalue;
-                    }
-                    update2[key + suffix] = value;
-                    dynfield = true;
-                }
-            });
-            if (dynfield) {
-                updates.push(update2);
-            }
-        }
-        await cursor?.forEach(updateDoc);
-        const result = await logExecution({
-            startMessage: `Dispatching updates for ${updates.length} documents`,
-            endMessage: 'Dispatched updates complete',
-            action: () => Search.updateDocuments(updates),
-            color: cyan,
-        });
-        try {
-            if (result) {
-                const { status } = JSON.parse(result).responseHeader;
-                console.log(status ? red(`Failed with status code (${status})`) : green('Success!'));
-            } else {
-                console.log(red('Solr is likely not running!'));
-            }
-        } catch (e) {
-            console.log(red('Error:'));
-            console.log(e);
-            console.log('\n');
-        }
-        await cursor?.close();
-    }
-
-    const suffixMap: { [type: string]: string | [string, string | ((json: any) => any)] } = {
-        number: '_n',
-        string: '_t',
-        boolean: '_b',
-        image: ['_t', 'url'],
-        video: ['_t', 'url'],
-        pdf: ['_t', 'url'],
-        audio: ['_t', 'url'],
-        web: ['_t', 'url'],
-        map: ['_t', 'url'],
-        date: ['_d', value => new Date(value.date).toISOString()],
-        proxy: ['_i', 'fieldId'],
-        prefetch_proxy: ['_i', 'fieldId'],
-        list: [
-            '_l',
-            list => {
-                const results = [];
-                // eslint-disable-next-line no-restricted-syntax
-                for (const value of list.fields) {
-                    const term = ToSearchTerm(value);
-                    if (term) {
-                        results.push(term.value);
-                    }
-                }
-                return results.length ? results : null;
-            },
-        ],
-    };
-
-    function ToSearchTerm(valIn: any): { suffix: string; value: any } | undefined {
-        let val = valIn;
-        if (val === null || val === undefined) {
-            return undefined;
-        }
-        const type = val.__type || typeof val;
-        let suffix = suffixMap[type];
-        if (!suffix) {
-            return undefined;
-        }
-
-        if (Array.isArray(suffix)) {
-            const accessor = suffix[1];
-            if (typeof accessor === 'function') {
-                val = accessor(val);
-            } else {
-                val = val[accessor];
-            }
-            // eslint-disable-next-line prefer-destructuring
-            suffix = suffix[0];
-        }
-
-        return { suffix, value: val };
-    }
-}
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index 8ab27130b..868373474 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -1,20 +1,18 @@
 import * as AdmZip from 'adm-zip';
 import * as formidable from 'formidable';
 import * as fs from 'fs';
-import { createReadStream, createWriteStream, unlink } from 'fs';
+import { unlink } from 'fs';
 import * as imageDataUri from 'image-data-uri';
-import { Jimp } from 'jimp';
 import * as path from 'path';
 import * as uuid from 'uuid';
 import { retrocycle } from '../../decycler/decycler';
 import { DashVersion } from '../../fields/DocSymbols';
-import { DashUploadUtils, InjectSize, SizeSuffix } from '../DashUploadUtils';
+import { DashUploadUtils, InjectSize, SizeSuffix, workerResample } from '../DashUploadUtils';
 import { Method, _success } from '../RouteManager';
 import { AcceptableMedia, Upload } from '../SharedMediaTypes';
 import { Directory, clientPathToFile, pathToDirectory, publicDirectory, serverPathToFile } from '../SocketData';
 import { Database } from '../database';
 import ApiManager, { Registration } from './ApiManager';
-import { SolrManager } from './SearchManager';
 
 export default class UploadManager extends ApiManager {
     protected initialize(register: Registration): void {
@@ -185,7 +183,7 @@ export default class UploadManager extends ApiManager {
                         let linkids: string[] = [];
                         try {
                             // eslint-disable-next-line no-restricted-syntax
-                            for (const name in Object.keys(files)) {
+                            for (const name in files) {
                                 if (Object.prototype.hasOwnProperty.call(files, name)) {
                                     const f = files[name];
                                     // eslint-disable-next-line no-continue
@@ -194,25 +192,17 @@ export default class UploadManager extends ApiManager {
                                     const zip = new AdmZip(path2.filepath);
                                     zip.getEntries().forEach(entry => {
                                         const entryName = entry.entryName.replace(/%%%/g, '/');
-                                        if (!entryName.startsWith('files/')) {
-                                            return;
-                                        }
-                                        const extension = path.extname(entryName);
-                                        const pathname = publicDirectory + '/' + entry.entryName;
-                                        const targetname = publicDirectory + '/' + entryName;
-                                        try {
-                                            zip.extractEntryTo(entry.entryName, publicDirectory, true, false);
-                                            createReadStream(pathname).pipe(createWriteStream(targetname));
-                                            Jimp.read(pathname).then(img => {
-                                                DashUploadUtils.imageResampleSizes(extension).forEach(({ width, suffix }) => {
-                                                    const outputPath = InjectSize(targetname, suffix);
-                                                    if (!width) createReadStream(pathname).pipe(createWriteStream(outputPath));
-                                                    else img.resize({ w: width }).write(outputPath as `${string}.${string}`);
-                                                });
-                                                unlink(pathname, () => {});
-                                            });
-                                        } catch (e) {
-                                            console.log(e);
+                                        if (entryName.startsWith('files/')) {
+                                            const pathname = publicDirectory + '/' + entry.entryName;
+                                            const targetname = publicDirectory + '/' + entryName;
+                                            try {
+                                                zip.extractEntryTo(entry.entryName, publicDirectory, true, false);
+                                                const extension = path.extname(targetname).toLowerCase();
+                                                const basefilename = targetname.substring(0, targetname.length - extension.length);
+                                                workerResample(pathname, basefilename.replace(/_o$/, '') + extension, SizeSuffix.Original, true);
+                                            } catch (e) {
+                                                console.log(e);
+                                            }
                                         }
                                     });
                                     const json = zip.getEntry('docs.json');
@@ -243,7 +233,6 @@ export default class UploadManager extends ApiManager {
                                     unlink(path2.filepath, () => {});
                                 }
                             }
-                            SolrManager.update();
                             res.send(JSON.stringify({ id, docids, linkids }) || 'error');
                         } catch (e) {
                             console.log(e);
@@ -286,15 +275,9 @@ export default class UploadManager extends ApiManager {
                 }
                 imageDataUri.outputFile(uri, serverPathToFile(Directory.images, InjectSize(filename, origSuffix))).then((savedName: string) => {
                     const ext = path.extname(savedName).toLowerCase();
+                    const outputPath = serverPathToFile(Directory.images, filename + ext);
                     if (AcceptableMedia.imageFormats.includes(ext)) {
-                        Jimp.read(savedName).then(img => {
-                            (!origSuffix ? [{ width: 400, suffix: SizeSuffix.Medium }] : Object.values(DashUploadUtils.Sizes)) //
-                                .forEach(({ width, suffix }) => {
-                                    const outputPath = serverPathToFile(Directory.images, InjectSize(filename, suffix) + ext);
-                                    if (!width) createReadStream(savedName).pipe(createWriteStream(outputPath));
-                                    else img.resize({ w: width }).write(outputPath as `${string}.${string}`);
-                                });
-                        });
+                        workerResample(savedName, outputPath, origSuffix, false);
                     }
                     res.send(clientPathToFile(Directory.images, filename + ext));
                 });
diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts
index 5cf86b2ae..1e55a885a 100644
--- a/src/server/DashUploadUtils.ts
+++ b/src/server/DashUploadUtils.ts
@@ -7,7 +7,7 @@ import * as ffmpeg from 'fluent-ffmpeg';
 import * as formidable from 'formidable';
 import { File } from 'formidable';
 import * as fs from 'fs';
-import { createReadStream, createWriteStream, existsSync, readFileSync, rename, unlinkSync, writeFile } from 'fs'; // import { Jimp } from "@jimp/core";
+import { createReadStream, createWriteStream, existsSync, readFileSync, rename, unlinkSync, writeFile } from 'fs';
 import { Jimp } from 'jimp';
 import * as md5File from 'md5-file';
 import * as path from 'path';
@@ -25,32 +25,38 @@ import { resolvedServerUrl } from './server_Initialization';
 import { Worker, isMainThread, parentPort } from 'worker_threads';
 
 // Create an array to store worker threads
-const workerThreads: Worker[] = [];
+enum workertasks {
+    JIMP = 'jimp',
+}
+const JimpWorker: Worker | undefined = isMainThread ? new Worker(__filename) : undefined;
+export const workerResample = (imgSourcePath: string, outputPath: string, origSuffix: SizeSuffix, unlinkSource: boolean) => {
+    JimpWorker?.postMessage({ task: workertasks.JIMP, imgSourcePath, outputPath, origSuffix, unlinkSource });
+};
+
 if (isMainThread) {
-    // Main thread code
-    // Create worker threads -- just one right to do image resampling
-    workerThreads.push(new Worker(__filename));
+    // main thread code if needed ...
 } else {
     // Worker thread code - Listens for messages from the main thread
-    parentPort?.on('message', message => workerResampleImage(message.task));
-    async function workerResampleImage(task: string) {
-        const [sourcePath, outputFileName, outputDirectory, unlinkSource] = task.split('::');
-        const sizes = DashUploadUtils.imageResampleSizes(path.extname(sourcePath));
-        const imgBuffer = await fs.readFileSync(sourcePath);
-        const outputPath = (suffix: SizeSuffix) => {
-            const writtenFile = InjectSize(outputFileName, suffix);
-            return path.resolve(outputDirectory, writtenFile);
-        };
-        await Jimp.fromBuffer(imgBuffer)
-            .then(img => sizes.filter(({ width }) => width).map(({ width, suffix }) => img.resize({ w: width }).write(outputPath(suffix) as `${string}.${string}`)))
-            .catch(e => {
-                console.log('ERROR' + e);
-            });
-        if (unlinkSource === 'true') {
-            unlinkSync(sourcePath);
+    parentPort?.on('message', message => {
+        switch (message.task) {
+            case workertasks.JIMP:
+                return workerResampleImage(message);
+            default:
         }
-
-        // … operations to be performed to execute the task
+    });
+
+    async function workerResampleImage(message: { imgSourcePath: string; outputPath: string; origSuffix: string; unlinkSource: boolean }) {
+        const { imgSourcePath, outputPath, origSuffix, unlinkSource } = message;
+        const sizes = !origSuffix ? [{ width: 400, suffix: SizeSuffix.Medium }] : DashUploadUtils.imageResampleSizes(path.extname(imgSourcePath));
+        // prettier-ignore
+        Jimp.read(imgSourcePath)
+            .then(img => 
+                sizes.forEach(({ width, suffix }) =>
+                    img.resize({ w: width || img.bitmap.width })
+                       .write(InjectSize(outputPath, suffix) as `${string}.${string}`)
+                ))
+            .catch(e => console.log('Error Jimp:', e))
+            .finally(() => unlinkSource && unlinkSync(imgSourcePath));
     }
 }
 
@@ -332,28 +338,22 @@ export namespace DashUploadUtils {
      * @param outputDirectory the directory to output to, usually Directory.Images
      * @returns a map with suffixes as keys and resized filenames as values.
      */
-    export async function outputResizedImages(imgSourcePath: string, outputFileName: string, outputDirectory: string, unlinkSource: boolean) {
+    export async function outputResizedImages(imgSourcePath: string, outputFileName: string, unlinkSource: boolean) {
         const writtenFiles: { [suffix: string]: string } = {};
-
-        const outputPath = (suffix: SizeSuffix) => {
-            writtenFiles[suffix] = InjectSize(outputFileName, suffix);
-            return path.resolve(outputDirectory, writtenFiles[suffix]);
-        };
-
+        const outputPath = path.resolve(pathToDirectory(Directory.images), outputFileName);
         const sizes = imageResampleSizes(path.extname(outputFileName));
-        const imgBuffer = fs.readFileSync(imgSourcePath);
+
         const imgReadStream = new Duplex();
-        imgReadStream.push(imgBuffer);
+        imgReadStream.push(fs.readFileSync(imgSourcePath));
         imgReadStream.push(null);
         await Promise.all(
             sizes.map(({ suffix }) => 
                 new Promise<unknown>(res =>
-                    imgReadStream.pipe(createWriteStream(outputPath(suffix))).on('close', res)
+                    imgReadStream.pipe(createWriteStream(writtenFiles[suffix] = InjectSize(outputPath, suffix))).on('close', res)
                 )
         )); // prettier-ignore
 
-        // Send a message to worker thread to resample image
-        workerThreads[0].postMessage({ task: imgSourcePath + '::' + outputFileName + '::' + outputDirectory + '::' + unlinkSource });
+        workerResample(imgSourcePath, outputPath, SizeSuffix.Original, unlinkSource);
         return writtenFiles;
     }
 
@@ -402,7 +402,7 @@ export namespace DashUploadUtils {
         } else {
             const unlinkSrcWhenFinished = isLocal().test(source) && cleanUp;
             try {
-                writtenFiles = await outputResizedImages(metadata.source, resolved, pathToDirectory(Directory.images), unlinkSrcWhenFinished);
+                writtenFiles = await outputResizedImages(metadata.source, resolved, unlinkSrcWhenFinished);
             } catch (e) {
                 // input is a blob or other, try reading it to create a metadata source file.
                 const reqSource = request(metadata.source);
@@ -414,7 +414,7 @@ export namespace DashUploadUtils {
                         .on('close', () => res())
                         .on('error', () => rej());
                 });
-                writtenFiles = await outputResizedImages(readSource, resolved, pathToDirectory(Directory.images), unlinkSrcWhenFinished);
+                writtenFiles = await outputResizedImages(readSource, resolved, unlinkSrcWhenFinished);
                 fs.unlink(readSource, err => console.log("Couldn't unlink temporary image file:" + readSource, err));
             }
         }
diff --git a/src/server/index.ts b/src/server/index.ts
index 3e0d86814..88dbd232d 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -8,7 +8,6 @@ import DataVizManager from './ApiManagers/DataVizManager';
 import DeleteManager from './ApiManagers/DeleteManager';
 import DownloadManager from './ApiManagers/DownloadManager';
 import GeneralGoogleManager from './ApiManagers/GeneralGoogleManager';
-import { SearchManager } from './ApiManagers/SearchManager';
 import SessionManager from './ApiManagers/SessionManager';
 import UploadManager from './ApiManagers/UploadManager';
 import UserManager from './ApiManagers/UserManager';
@@ -67,7 +66,6 @@ function routeSetter({ addSupervisedRoute, logRegistrationOutcome }: RouteManage
         new UserManager(),
         new UploadManager(),
         new DownloadManager(),
-        new SearchManager(),
         new DeleteManager(),
         new UtilManager(),
         new GeneralGoogleManager(),
-- 
cgit v1.2.3-70-g09d2

