Picsur/backend/src/workers/sharp/sharp.worker.ts

124 lines
2.9 KiB
TypeScript
Raw Normal View History

2022-08-27 12:24:26 +00:00
import { FileType } from 'picsur-shared/dist/dto/mimes.dto';
2022-06-27 11:22:48 +00:00
import posix from 'posix.js';
2022-05-01 21:29:56 +00:00
import { Sharp } from 'sharp';
import {
SharpWorkerFinishOptions,
SharpWorkerInitMessage,
SharpWorkerOperationMessage,
SharpWorkerRecieveMessage,
2022-09-06 14:32:16 +00:00
SharpWorkerSendMessage,
2022-05-01 21:29:56 +00:00
} from './sharp.message';
import { UniversalSharpIn, UniversalSharpOut } from './universal-sharp';
export class SharpWorker {
private startTime: number = 0;
private sharpi: Sharp | null = null;
constructor() {
this.setup();
}
private setup() {
if (process.send === undefined) {
return this.purge('This is not a worker process');
}
const memoryLimit = parseInt(process.env['MEMORY_LIMIT_MB'] ?? '');
2022-06-05 10:20:16 +00:00
2022-05-01 21:29:56 +00:00
if (isNaN(memoryLimit) || memoryLimit <= 0) {
return this.purge('MEMORY_LIMIT_MB environment variable is not set');
}
posix.setrlimit('data', {
soft: 1000 * 1000 * memoryLimit,
hard: 1000 * 1000 * memoryLimit,
});
process.on('message', this.messageHandler.bind(this));
this.sendMessage({
type: 'ready',
});
}
private messageHandler(message: SharpWorkerSendMessage): void {
if (message.type === 'init') {
this.init(message);
} else if (message.type === 'operation') {
this.operation(message);
} else if (message.type === 'finish') {
2022-08-27 12:24:26 +00:00
this.finish(message.filetype, message.options);
2022-05-01 21:29:56 +00:00
} else {
return this.purge('Unknown message type');
}
}
private init(message: SharpWorkerInitMessage): void {
if (this.sharpi !== null) {
return this.purge('Already initialized');
}
this.startTime = Date.now();
2022-09-06 14:32:16 +00:00
this.sharpi = UniversalSharpIn(
message.image,
message.filetype,
message.options,
);
2022-05-01 21:29:56 +00:00
}
private operation(message: SharpWorkerOperationMessage): void {
if (this.sharpi === null) {
return this.purge('Not initialized');
}
const operation = message.operation;
message.operation.parameters;
this.sharpi = (this.sharpi[operation.name] as any)(...operation.parameters);
}
private async finish(
2022-08-27 12:24:26 +00:00
filetype: FileType,
2022-05-01 21:29:56 +00:00
options: SharpWorkerFinishOptions,
): Promise<void> {
if (this.sharpi === null) {
return this.purge('Not initialized');
}
const sharpi = this.sharpi;
this.sharpi = null;
try {
2022-08-27 12:24:26 +00:00
const result = await UniversalSharpOut(sharpi, filetype, options);
2022-05-01 21:29:56 +00:00
const processingTime = Date.now() - this.startTime;
this.sendMessage({
type: 'result',
processingTime,
result,
});
} catch (e) {
return this.purge(e);
}
}
private sendMessage(message: SharpWorkerRecieveMessage): void {
if (process.send === undefined) {
return this.purge('This is not a worker process');
}
process.send(message);
}
private purge(reason: any): void {
if (typeof reason === 'string') {
console.error(new Error(reason));
} else {
console.error(reason);
}
process.exit(1);
}
}
new SharpWorker();