From b235e116167a06b6d36e2962dd3f610839f18974 Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 1 Sep 2024 00:11:36 -0400 Subject: updated to latest Jimp. fixed lag dropping images from filesystem by using worker threads. --- src/server/DashUploadUtils.ts | 94 ++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 41 deletions(-) (limited to 'src/server/DashUploadUtils.ts') diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index 8f012f783..5cf86b2ae 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -1,5 +1,5 @@ import axios from 'axios'; -import { spawn, exec } from 'child_process'; +import { exec, spawn } from 'child_process'; import { green, red } from 'colors'; import { ExifData, ExifImage } from 'exif'; import * as exifr from 'exifr'; @@ -7,9 +7,8 @@ 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'; -import * as autorotate from 'jpeg-autorotate'; +import { createReadStream, createWriteStream, existsSync, readFileSync, rename, unlinkSync, writeFile } from 'fs'; // import { Jimp } from "@jimp/core"; +import { Jimp } from 'jimp'; import * as md5File from 'md5-file'; import * as path from 'path'; import { basename } from 'path'; @@ -23,6 +22,38 @@ import { AcceptableMedia, Upload } from './SharedMediaTypes'; import { Directory, clientPathToFile, filesDirectory, pathToDirectory, publicDirectory, serverPathToFile } from './SocketData'; import { resolvedServerUrl } from './server_Initialization'; +import { Worker, isMainThread, parentPort } from 'worker_threads'; + +// Create an array to store worker threads +const workerThreads: Worker[] = []; +if (isMainThread) { + // Main thread code + // Create worker threads -- just one right to do image resampling + workerThreads.push(new Worker(__filename)); +} 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); + } + + // … operations to be performed to execute the task + } +} + // eslint-disable-next-line @typescript-eslint/no-var-requires const requestImageSize = require('../client/util/request-image-size'); @@ -277,15 +308,6 @@ export namespace DashUploadUtils { } }; - async function correctRotation(imgSourcePath: string) { - const buffer = fs.readFileSync(imgSourcePath); - try { - return (await autorotate.rotate(buffer, { quality: 30 })).buffer; - } catch (e) { - return buffer; - } - } - /** * define the resizers to use * @param ext the extension @@ -310,38 +332,29 @@ 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) { + export async function outputResizedImages(imgSourcePath: string, outputFileName: string, outputDirectory: string, unlinkSource: boolean) { const writtenFiles: { [suffix: string]: string } = {}; - const sizes = imageResampleSizes(path.extname(outputFileName)); - const imgBuffer = await correctRotation(imgSourcePath); - const imgReadStream = new Duplex(); - imgReadStream.push(imgBuffer); - imgReadStream.push(null); const outputPath = (suffix: SizeSuffix) => { writtenFiles[suffix] = InjectSize(outputFileName, suffix); return path.resolve(outputDirectory, writtenFiles[suffix]); }; + + const sizes = imageResampleSizes(path.extname(outputFileName)); + const imgBuffer = fs.readFileSync(imgSourcePath); + const imgReadStream = new Duplex(); + imgReadStream.push(imgBuffer); + imgReadStream.push(null); await Promise.all( - sizes.filter(({ width }) => !width).map(({ suffix }) => - new Promise(res => { - imgReadStream.pipe(createWriteStream(outputPath(suffix))).on('close', res); - }) + sizes.map(({ suffix }) => + new Promise(res => + imgReadStream.pipe(createWriteStream(outputPath(suffix))).on('close', res) + ) )); // prettier-ignore - return Jimp.read(imgBuffer) - .then(async imgIn => { - let img = imgIn; - await Promise.all( sizes.filter(({ width }) => width).map(({ width, suffix }) => { - img = img.resize(width, Jimp.AUTO).write(outputPath(suffix)); - return img; - } )); // prettier-ignore - return writtenFiles; - }) - .catch(e => { - console.log('ERROR' + e); - return writtenFiles; - }); + // Send a message to worker thread to resample image + workerThreads[0].postMessage({ task: imgSourcePath + '::' + outputFileName + '::' + outputDirectory + '::' + unlinkSource }); + return writtenFiles; } /** @@ -387,8 +400,9 @@ export namespace DashUploadUtils { writtenFiles = {}; } } else { + const unlinkSrcWhenFinished = isLocal().test(source) && cleanUp; try { - writtenFiles = await outputResizedImages(metadata.source, resolved, pathToDirectory(Directory.images)); + writtenFiles = await outputResizedImages(metadata.source, resolved, pathToDirectory(Directory.images), unlinkSrcWhenFinished); } catch (e) { // input is a blob or other, try reading it to create a metadata source file. const reqSource = request(metadata.source); @@ -400,16 +414,14 @@ export namespace DashUploadUtils { .on('close', () => res()) .on('error', () => rej()); }); - writtenFiles = await outputResizedImages(readSource, resolved, pathToDirectory(Directory.images)); + writtenFiles = await outputResizedImages(readSource, resolved, pathToDirectory(Directory.images), unlinkSrcWhenFinished); fs.unlink(readSource, err => console.log("Couldn't unlink temporary image file:" + readSource, err)); } } Array.from(Object.keys(writtenFiles)).forEach(suffix => { information.accessPaths[suffix] = getAccessPaths(images, writtenFiles[suffix]); }); - if (isLocal().test(source) && cleanUp) { - unlinkSync(source); - } + return information; }; -- cgit v1.2.3-70-g09d2 From a958577d4c27b276aa37484e3f895e196138b17c Mon Sep 17 00:00:00 2001 From: bobzel 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/server/DashUploadUtils.ts') 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 { 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() { @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({ - 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(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