@e-mc/compress 0.11.7 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -9
- package/index.js +258 -125
- package/package.json +3 -3
- package/worker/plugin-image.js +34 -0
- package/worker/sfnt2woff.js +14 -0
- package/worker/system-brotli.js +40 -0
- package/worker/system-gzip.js +40 -0
- package/worker/wawoff2-compress.js +14 -0
- package/worker/wawoff2-decompress.js +14 -0
- package/worker/woff2sfnt.js +14 -0
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @e-mc/compress
|
|
2
2
|
|
|
3
|
-
* NodeJS
|
|
4
|
-
*
|
|
3
|
+
* NodeJS 18
|
|
4
|
+
* ES2022
|
|
5
5
|
|
|
6
6
|
## General Usage
|
|
7
7
|
|
|
@@ -9,16 +9,16 @@
|
|
|
9
9
|
|
|
10
10
|
## Interface
|
|
11
11
|
|
|
12
|
-
* [View Source](https://www.unpkg.com/@e-mc/types@0.
|
|
12
|
+
* [View Source](https://www.unpkg.com/@e-mc/types@0.12.0/lib/index.d.ts)
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
import type { IModule, ModuleConstructor } from "./index";
|
|
16
|
-
import type { BufferResult, CompressFormat, CompressLevel, ReadableOptions, TryFileCompressor } from "./compress";
|
|
16
|
+
import type { BrotliCompressLevel, BufferResult, CompressFormat, CompressLevel, ReadableOptions, TryFileCompressor } from "./compress";
|
|
17
17
|
import type { CompressModule, CompressSettings } from "./settings";
|
|
18
18
|
|
|
19
19
|
import type { WriteStream } from "node:fs";
|
|
20
20
|
import type { Readable } from "node:stream";
|
|
21
|
-
import type { BrotliCompress, Gzip } from "node:zlib";
|
|
21
|
+
import type { BrotliCompress, BrotliOptions, Gzip, ZlibOptions } from "node:zlib";
|
|
22
22
|
|
|
23
23
|
interface ICompress extends IModule {
|
|
24
24
|
module: CompressModule;
|
|
@@ -30,15 +30,18 @@ interface ICompress extends IModule {
|
|
|
30
30
|
getLevel(value: string, fallback?: number): number | undefined;
|
|
31
31
|
getReadable(file: string | URL | Buffer, options?: ReadableOptions): Readable;
|
|
32
32
|
createGzip(file: string | Buffer, options?: CompressLevel): Gzip;
|
|
33
|
-
createBrotliCompress(file: string | Buffer, options?:
|
|
33
|
+
createBrotliCompress(file: string | Buffer, options?: BrotliCompressLevel): BrotliCompress;
|
|
34
34
|
createWriteStreamAsGzip(file: string | Buffer, output: string, options?: CompressLevel): WriteStream;
|
|
35
35
|
createWriteStreamAsBrotli(file: string | Buffer, output: string, options?: CompressLevel): WriteStream;
|
|
36
|
+
intoGzipStream(output: string, options?: ZlibOptions): WriteStream;
|
|
37
|
+
intoBrotliStream(output: string, options?: BrotliOptions): WriteStream;
|
|
36
38
|
writeGzip(file: string | Buffer, output: string, options?: CompressLevel): Promise<void>;
|
|
37
39
|
writeBrotli(file: string | Buffer, output: string, options?: CompressLevel): Promise<void>;
|
|
38
40
|
tryFile(file: string | Buffer, options: CompressFormat): Promise<BufferResult>;
|
|
39
41
|
tryFile(file: string | Buffer, output: string, options?: CompressFormat): Promise<BufferResult>;
|
|
40
42
|
tryImage(file: string, options: CompressFormat): Promise<BufferResult>;
|
|
41
43
|
tryImage(file: string | Buffer, output: string, options?: CompressFormat): Promise<BufferResult>;
|
|
44
|
+
hasPermission(type: string, options?: unknown): boolean;
|
|
42
45
|
set chunkSize(value: number | string | undefined): void;
|
|
43
46
|
get chunkSize(): number | undefined;
|
|
44
47
|
get settings(): CompressSettings;
|
|
@@ -46,6 +49,7 @@ interface ICompress extends IModule {
|
|
|
46
49
|
|
|
47
50
|
interface CompressConstructor extends ModuleConstructor {
|
|
48
51
|
singleton(): ICompress;
|
|
52
|
+
asBuffer(data: Buffer | Uint8Array): Buffer;
|
|
49
53
|
readonly prototype: ICompress;
|
|
50
54
|
new(module?: CompressModule): ICompress;
|
|
51
55
|
}
|
|
@@ -116,9 +120,9 @@ instance.tryImage("/tmp/image.png", "/path/output/compressed.png", options)
|
|
|
116
120
|
|
|
117
121
|
## References
|
|
118
122
|
|
|
119
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
120
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
121
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
123
|
+
- https://www.unpkg.com/@e-mc/types@0.12.0/lib/squared.d.ts
|
|
124
|
+
- https://www.unpkg.com/@e-mc/types@0.12.0/lib/compress.d.ts
|
|
125
|
+
- https://www.unpkg.com/@e-mc/types@0.12.0/lib/settings.d.ts
|
|
122
126
|
|
|
123
127
|
* https://www.npmjs.com/package/@types/node
|
|
124
128
|
|
package/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var _a;
|
|
3
2
|
const path = require("node:path");
|
|
4
3
|
const fs = require("node:fs");
|
|
5
4
|
const stream = require("node:stream");
|
|
6
5
|
const zlib = require("node:zlib");
|
|
7
6
|
const wawoff2 = require("wawoff2");
|
|
8
7
|
const types_1 = require("@e-mc/types");
|
|
9
|
-
const
|
|
8
|
+
const core_1 = require("@e-mc/core");
|
|
10
9
|
const { toSfnt, toWoff } = require('woff2sfnt-sfnt2woff');
|
|
11
|
-
const
|
|
10
|
+
const kCompress = Symbol.for('compress:constructor');
|
|
11
|
+
function createWorker(filename) {
|
|
12
|
+
return core_1.WorkerChannel.create(path.join(__dirname, 'worker', filename), 'EMC_COMPRESS');
|
|
13
|
+
}
|
|
14
|
+
const SUPPORTED_NODE21 = (0, types_1.supported)(21);
|
|
12
15
|
const CACHE_IMAGE = {};
|
|
13
16
|
const CACHE_FONT = Object.create(null);
|
|
14
17
|
const CACHE_FONTFROM = {};
|
|
@@ -16,14 +19,15 @@ const CACHE_FONTTO = {};
|
|
|
16
19
|
const CACHE_INIT = [false, false];
|
|
17
20
|
let SINGLETON_INSTANCE;
|
|
18
21
|
let TEMP_DIR = '';
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
const WORKER = new core_1.WorkerGroup(parseInt(process.env.EMC_COMPRESS_WORKER_GROUP_MAX || '0'));
|
|
23
|
+
WORKER
|
|
24
|
+
.add('otf', createWorker('sfnt2woff.js'))
|
|
25
|
+
.add('woff', createWorker('woff2sfnt.js'))
|
|
26
|
+
.add('woff2', createWorker('wawoff2-decompress.js'))
|
|
27
|
+
.add('ttf', createWorker('wawoff2-compress.js'))
|
|
28
|
+
.add('image', createWorker('plugin-image.js'))
|
|
29
|
+
.add('gz', createWorker('system-gzip.js'))
|
|
30
|
+
.add('br', createWorker('system-brotli.js'));
|
|
27
31
|
function setCacheData(instance, index) {
|
|
28
32
|
if (CACHE_INIT[index]) {
|
|
29
33
|
return true;
|
|
@@ -34,7 +38,7 @@ function setCacheData(instance, index) {
|
|
|
34
38
|
if (TEMP_DIR) {
|
|
35
39
|
if (expires === 0) {
|
|
36
40
|
if (CACHE_INIT.every(value => !value)) {
|
|
37
|
-
|
|
41
|
+
core_1.Module.removeDir(TEMP_DIR, true);
|
|
38
42
|
}
|
|
39
43
|
settings.cache_expires = 0;
|
|
40
44
|
}
|
|
@@ -79,15 +83,19 @@ function setCacheData(instance, index) {
|
|
|
79
83
|
}
|
|
80
84
|
return CACHE_INIT[index] = true;
|
|
81
85
|
}
|
|
82
|
-
function getOutputSize(startLength, data) {
|
|
86
|
+
function getOutputSize(startLength, data, worker) {
|
|
83
87
|
if (startLength === 0 || !data) {
|
|
84
|
-
return '';
|
|
88
|
+
return worker ? ' (worker)' : '';
|
|
85
89
|
}
|
|
86
90
|
const offset = Buffer.byteLength(data) - startLength;
|
|
87
|
-
return ` (${(offset > 0 ? '+' : '') + (0, types_1.formatSize)(offset)})`;
|
|
91
|
+
return ` (${(worker ? 'worker: ' : '') + (offset > 0 ? '+' : '') + (0, types_1.formatSize)(offset)})`;
|
|
88
92
|
}
|
|
89
93
|
const sanitizePath = (value) => value.replace(/[\\/]/g, '_');
|
|
90
|
-
|
|
94
|
+
const getWorkerTimeout = (options, value) => core_1.WorkerGroup.checkTimeout(typeof options.worker === 'number' && options.worker > 0 ? options.worker : value, true);
|
|
95
|
+
const applyBrotliMode = (params, value) => params[zlib.constants.BROTLI_PARAM_MODE] = value.includes('text/') ? zlib.constants.BROTLI_MODE_TEXT : value.includes('font/') ? zlib.constants.BROTLI_MODE_FONT : zlib.constants.BROTLI_MODE_GENERIC;
|
|
96
|
+
class Compress extends core_1.Module {
|
|
97
|
+
module;
|
|
98
|
+
static [kCompress] = true;
|
|
91
99
|
static singleton() {
|
|
92
100
|
if (!SINGLETON_INSTANCE) {
|
|
93
101
|
SINGLETON_INSTANCE = new Compress();
|
|
@@ -99,17 +107,20 @@ class Compress extends module_1 {
|
|
|
99
107
|
}
|
|
100
108
|
return SINGLETON_INSTANCE;
|
|
101
109
|
}
|
|
110
|
+
static asBuffer(data) {
|
|
111
|
+
return data instanceof Uint8Array ? Buffer.from(data.buffer, data.byteOffset, data.byteLength) : data;
|
|
112
|
+
}
|
|
113
|
+
level = {
|
|
114
|
+
gz: 9,
|
|
115
|
+
br: 11,
|
|
116
|
+
zopfli: 15
|
|
117
|
+
};
|
|
118
|
+
compressors = {};
|
|
119
|
+
_moduleName = 'compress';
|
|
120
|
+
#chunkSize = undefined;
|
|
102
121
|
constructor(module = {}) {
|
|
103
122
|
super();
|
|
104
123
|
this.module = module;
|
|
105
|
-
this.level = {
|
|
106
|
-
gz: 9,
|
|
107
|
-
br: 11,
|
|
108
|
-
zopfli: 15
|
|
109
|
-
};
|
|
110
|
-
this.compressors = {};
|
|
111
|
-
this._moduleName = 'compress';
|
|
112
|
-
this[_a] = undefined;
|
|
113
124
|
}
|
|
114
125
|
init(...args) {
|
|
115
126
|
let { gzip_level, brotli_quality, zopfli_iterations, chunk_size } = (0, types_1.isPlainObject)(args[0]) && args[0].settings || this.settings;
|
|
@@ -153,14 +164,14 @@ class Compress extends module_1 {
|
|
|
153
164
|
return stream.Readable.from(file);
|
|
154
165
|
}
|
|
155
166
|
try {
|
|
156
|
-
if (!options?.throwsPermission || this.canRead(file, { ownPermissionOnly: true })) {
|
|
167
|
+
if (!options?.throwsPermission && !process.permission || this.canRead(file, { ownPermissionOnly: true })) {
|
|
157
168
|
return fs.createReadStream(file);
|
|
158
169
|
}
|
|
159
170
|
options = undefined;
|
|
160
171
|
throw (0, types_1.errorValue)("Operation not permitted", file.toString());
|
|
161
172
|
}
|
|
162
173
|
catch (err) {
|
|
163
|
-
if (!options || options.throwsPermission &&
|
|
174
|
+
if (!options || options.throwsPermission && core_1.Module.isErrorCode(err, 'EACCES') || options.throwsDoesNotExist && core_1.Module.isErrorCode(err, 'ENOENT')) {
|
|
164
175
|
throw err;
|
|
165
176
|
}
|
|
166
177
|
}
|
|
@@ -172,15 +183,18 @@ class Compress extends module_1 {
|
|
|
172
183
|
({ algorithm, level, chunkSize } = options);
|
|
173
184
|
}
|
|
174
185
|
if (algorithm === 'zopfli') {
|
|
175
|
-
|
|
176
|
-
const
|
|
186
|
+
try {
|
|
187
|
+
const lib = require('node-zopfli');
|
|
188
|
+
const opts = (0, types_1.isPlainObject)(this.module.zopfli) ? { ...this.module.zopfli } : {};
|
|
177
189
|
if (typeof level === 'number') {
|
|
178
|
-
|
|
190
|
+
opts.numiterations = level;
|
|
179
191
|
}
|
|
180
192
|
else {
|
|
181
|
-
|
|
193
|
+
opts.numiterations ??= this.level.zopfli;
|
|
182
194
|
}
|
|
183
|
-
return this.getReadable(file, options).pipe(
|
|
195
|
+
return this.getReadable(file, options).pipe(lib.createGzip(opts));
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
184
198
|
}
|
|
185
199
|
level = undefined;
|
|
186
200
|
}
|
|
@@ -213,7 +227,7 @@ class Compress extends module_1 {
|
|
|
213
227
|
else {
|
|
214
228
|
brotli = { params };
|
|
215
229
|
}
|
|
216
|
-
params
|
|
230
|
+
applyBrotliMode(params, mimeType || '');
|
|
217
231
|
try {
|
|
218
232
|
params[zlib.constants.BROTLI_PARAM_SIZE_HINT] = typeof file === 'string' ? fs.statSync(file).size : Buffer.byteLength(file);
|
|
219
233
|
}
|
|
@@ -233,6 +247,12 @@ class Compress extends module_1 {
|
|
|
233
247
|
createWriteStreamAsBrotli(file, output, options) {
|
|
234
248
|
return this.createBrotliCompress(file, options).pipe(fs.createWriteStream(output));
|
|
235
249
|
}
|
|
250
|
+
intoGzipStream(output, options) {
|
|
251
|
+
return zlib.createGzip(options).pipe(fs.createWriteStream(output));
|
|
252
|
+
}
|
|
253
|
+
intoBrotliStream(output, options) {
|
|
254
|
+
return zlib.createBrotliCompress(options).pipe(fs.createWriteStream(output));
|
|
255
|
+
}
|
|
236
256
|
async writeGzip(file, output, options) {
|
|
237
257
|
return new Promise((resolve, reject) => {
|
|
238
258
|
this.createWriteStreamAsGzip(file, output, options)
|
|
@@ -255,26 +275,34 @@ class Compress extends module_1 {
|
|
|
255
275
|
if (!(0, types_1.isString)(output)) {
|
|
256
276
|
output = typeof file === 'string' ? file : '';
|
|
257
277
|
}
|
|
278
|
+
if (output && !this.canWrite(output, { ownPermissionOnly: true })) {
|
|
279
|
+
return Promise.reject((0, types_1.errorValue)("Operation not permitted", output));
|
|
280
|
+
}
|
|
258
281
|
options ||= {};
|
|
259
|
-
const { filename, startTime = process.hrtime.bigint(), timeout = 0
|
|
282
|
+
const { filename, startTime = process.hrtime.bigint(), timeout = 0 } = options;
|
|
260
283
|
let format = options.format, hash = options.etag;
|
|
261
|
-
if (!format) {
|
|
284
|
+
if (!(0, types_1.isString)(format)) {
|
|
262
285
|
return Promise.reject((0, types_1.errorValue)("Missing option \"format\"", output || filename));
|
|
263
286
|
}
|
|
264
|
-
const cache = this.settings.cache ? !!(hash && (hash =
|
|
287
|
+
const cache = this.settings.cache ? !!(hash && (hash = core_1.Module.asHash(hash)) || Buffer.isBuffer(file) && (hash = core_1.Module.asHash(file))) : false;
|
|
288
|
+
format = format.toLowerCase();
|
|
265
289
|
return new Promise((resolve, reject) => {
|
|
266
|
-
let timer = null, startLength = 0,
|
|
290
|
+
let timer = null, worker = null, startLength = 0, closed = false;
|
|
267
291
|
const endProcess = (err, data = null, ext, result, fromCache) => {
|
|
292
|
+
if (closed) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
268
295
|
if (timer) {
|
|
269
296
|
clearTimeout(timer);
|
|
270
297
|
}
|
|
298
|
+
closed = true;
|
|
271
299
|
if (err) {
|
|
272
300
|
reject(err);
|
|
273
301
|
return;
|
|
274
302
|
}
|
|
275
303
|
if (!fromCache) {
|
|
276
304
|
const status = (0, types_1.isString)(result) ? path.basename(result) : filename || "Completed";
|
|
277
|
-
this.writeTimeProcess(ext || format, status + getOutputSize(startLength, data), startTime, { type: 8, sessionId, broadcastId });
|
|
305
|
+
this.writeTimeProcess(ext || format, status + getOutputSize(startLength, data, !!worker), startTime, { type: 8, sessionId: options.sessionId, broadcastId: options.broadcastId });
|
|
278
306
|
}
|
|
279
307
|
if (result) {
|
|
280
308
|
options.outFile = result;
|
|
@@ -287,14 +315,19 @@ class Compress extends module_1 {
|
|
|
287
315
|
const startProcess = (compressing) => {
|
|
288
316
|
if (timeout > 0) {
|
|
289
317
|
timer = setTimeout(() => {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
318
|
+
if (worker) {
|
|
319
|
+
void worker.terminate();
|
|
320
|
+
}
|
|
321
|
+
endProcess((0, types_1.errorValue)(worker ? "Worker did not finish" : "Timeout was exceeded", format));
|
|
322
|
+
}, worker ? getWorkerTimeout(options, timeout) : timeout);
|
|
293
323
|
}
|
|
294
|
-
this.formatMessage(8, format, [compressing ? 'Compressing file...' : 'Decompressing file...', filename || (output ? path.basename(output) : '')], (0, types_1.isString)(file) ? file : '', { titleColor: 'magenta', sessionId, broadcastId });
|
|
324
|
+
this.formatMessage(8, format, [compressing ? 'Compressing file...' : 'Decompressing file...', filename || (output ? path.basename(output) : '')], (0, types_1.isString)(file) ? file : '', { titleColor: 'magenta', sessionId: options.sessionId, broadcastId: options.broadcastId });
|
|
295
325
|
};
|
|
296
326
|
try {
|
|
297
327
|
const writeFont = (data, ext, from) => {
|
|
328
|
+
if (closed) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
298
331
|
if (output) {
|
|
299
332
|
const pathname = (0, types_1.renameExt)(output, ext);
|
|
300
333
|
fs.writeFile(pathname, data, err => {
|
|
@@ -312,7 +345,7 @@ class Compress extends module_1 {
|
|
|
312
345
|
if (cache) {
|
|
313
346
|
const pathname = path.join(from, ext);
|
|
314
347
|
let tempFont;
|
|
315
|
-
if (TEMP_DIR &&
|
|
348
|
+
if (TEMP_DIR && core_1.Module.createDir(tempFont = path.join(TEMP_DIR, pathname))) {
|
|
316
349
|
tempFont = path.join(tempFont, hash);
|
|
317
350
|
}
|
|
318
351
|
else {
|
|
@@ -332,7 +365,7 @@ class Compress extends module_1 {
|
|
|
332
365
|
const cacheKey = from + `_${to}_` + hash;
|
|
333
366
|
const tempFont = CACHE_FONT[cacheKey];
|
|
334
367
|
if (tempFont) {
|
|
335
|
-
if (
|
|
368
|
+
if (core_1.Module.isPath(tempFont[0])) {
|
|
336
369
|
try {
|
|
337
370
|
const data = fs.readFileSync(tempFont[0]);
|
|
338
371
|
let pathname;
|
|
@@ -343,7 +376,7 @@ class Compress extends module_1 {
|
|
|
343
376
|
else {
|
|
344
377
|
endProcess(null, data, to, '', true);
|
|
345
378
|
}
|
|
346
|
-
this.formatMessage(8, from, [pathname ? path.basename(pathname) : "Completed" + ` -> font/${to}`, 'cache'], tempFont[1].toLocaleString(), { ...
|
|
379
|
+
this.formatMessage(8, from, [pathname ? path.basename(pathname) : "Completed" + ` -> font/${to}`, 'cache'], tempFont[1].toLocaleString(), { ...core_1.Module.LOG_STYLE_NOTICE, hintBold: true, sessionId: options.sessionId, broadcastId: options.broadcastId });
|
|
347
380
|
return true;
|
|
348
381
|
}
|
|
349
382
|
catch {
|
|
@@ -354,14 +387,50 @@ class Compress extends module_1 {
|
|
|
354
387
|
return false;
|
|
355
388
|
}
|
|
356
389
|
};
|
|
357
|
-
const errorResponse = (font) => {
|
|
358
|
-
endProcess((0, types_1.errorValue)(
|
|
390
|
+
const errorResponse = (font, message = "Unsupported MIME") => {
|
|
391
|
+
endProcess((0, types_1.errorValue)(message, (font?.mime || "Unknown") + ': ' + (output || filename || "Unknown")));
|
|
359
392
|
};
|
|
360
|
-
const
|
|
393
|
+
const shared = Buffer.isBuffer(file);
|
|
394
|
+
let data;
|
|
395
|
+
if (shared) {
|
|
396
|
+
data = file;
|
|
397
|
+
}
|
|
398
|
+
else if (this.canRead(file, { ownPermissionOnly: true })) {
|
|
399
|
+
data = fs.readFileSync(file);
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
reject((0, types_1.errorValue)("Operation not permitted", file));
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
361
405
|
startLength = Buffer.byteLength(data);
|
|
362
|
-
switch (format
|
|
406
|
+
switch (format) {
|
|
363
407
|
case 'gz':
|
|
364
408
|
case 'br': {
|
|
409
|
+
if (this.hasPermission('worker', options)) {
|
|
410
|
+
const workerOptions = { chunkSize: options.chunkSize ?? this.chunkSize };
|
|
411
|
+
if (format === 'gz') {
|
|
412
|
+
workerOptions.level = options.level ?? this.level.gz;
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
workerOptions.params = { [zlib.constants.BROTLI_PARAM_QUALITY]: options.level ?? this.level.br };
|
|
416
|
+
applyBrotliMode(workerOptions.params, options.mimeType || '');
|
|
417
|
+
}
|
|
418
|
+
const endWorker = (result) => {
|
|
419
|
+
if ((0, types_1.isString)(result)) {
|
|
420
|
+
endProcess(null, null, format, result);
|
|
421
|
+
}
|
|
422
|
+
else if (result) {
|
|
423
|
+
endProcess(null, result, format);
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
endProcess((0, types_1.errorValue)("Worker did not finish", output));
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
if (worker = WORKER.get(format).sendObject({ data, options: workerOptions, output }, shared || SUPPORTED_NODE21 ? [] : [data.buffer], endWorker)) {
|
|
430
|
+
startProcess(true);
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
365
434
|
startProcess(true);
|
|
366
435
|
let transform, chunks;
|
|
367
436
|
if (output) {
|
|
@@ -376,12 +445,10 @@ class Compress extends module_1 {
|
|
|
376
445
|
}
|
|
377
446
|
transform
|
|
378
447
|
.on('finish', () => {
|
|
379
|
-
|
|
380
|
-
endProcess(null, chunks && Buffer.concat(chunks), format, output);
|
|
381
|
-
}
|
|
448
|
+
endProcess(null, chunks && Buffer.concat(chunks), format, output);
|
|
382
449
|
})
|
|
383
450
|
.on('error', (err) => {
|
|
384
|
-
|
|
451
|
+
transform.destroy();
|
|
385
452
|
endProcess(err);
|
|
386
453
|
});
|
|
387
454
|
break;
|
|
@@ -391,36 +458,52 @@ class Compress extends module_1 {
|
|
|
391
458
|
if (hasFont()) {
|
|
392
459
|
return;
|
|
393
460
|
}
|
|
394
|
-
startProcess(false);
|
|
395
461
|
const checkResult = (result, from) => {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
462
|
+
if (result) {
|
|
463
|
+
void core_1.Module.resolveMime(result).then(font => {
|
|
464
|
+
switch (font?.mime) {
|
|
465
|
+
case "font/ttf":
|
|
466
|
+
case "font/otf":
|
|
467
|
+
writeFont(result, font.ext, from);
|
|
468
|
+
break;
|
|
469
|
+
default:
|
|
470
|
+
errorResponse(font);
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
errorResponse(null, "Worker did not finish");
|
|
477
|
+
}
|
|
407
478
|
};
|
|
408
|
-
void
|
|
479
|
+
void core_1.Module.resolveMime(data)
|
|
409
480
|
.then(font => {
|
|
410
481
|
switch (font?.mime) {
|
|
411
482
|
case "font/woff":
|
|
412
483
|
if (cache) {
|
|
413
484
|
CACHE_FONTFROM[hash] = 'woff';
|
|
414
485
|
}
|
|
415
|
-
|
|
486
|
+
if (this.hasPermission('worker', options) && (worker = WORKER.get('woff').sendBuffer(data, shared, checkResult, 'woff'))) {
|
|
487
|
+
startProcess(false);
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
startProcess(false);
|
|
491
|
+
checkResult(toSfnt(data), 'woff');
|
|
492
|
+
}
|
|
416
493
|
break;
|
|
417
494
|
case "font/woff2":
|
|
418
495
|
if (cache) {
|
|
419
496
|
CACHE_FONTFROM[hash] = 'woff2';
|
|
420
497
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
}
|
|
498
|
+
if (this.hasPermission('worker', options) && (worker = WORKER.get('woff2').sendBuffer(data, shared, checkResult, 'woff2'))) {
|
|
499
|
+
startProcess(false);
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
startProcess(false);
|
|
503
|
+
void wawoff2.decompress(data).then(woff => {
|
|
504
|
+
checkResult(woff, 'woff2');
|
|
505
|
+
});
|
|
506
|
+
}
|
|
424
507
|
break;
|
|
425
508
|
default:
|
|
426
509
|
errorResponse(font);
|
|
@@ -435,33 +518,50 @@ class Compress extends module_1 {
|
|
|
435
518
|
if (hasFont()) {
|
|
436
519
|
return;
|
|
437
520
|
}
|
|
438
|
-
const checkResult = (result,
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
521
|
+
const checkResult = (result, from, mimeType) => {
|
|
522
|
+
if (result) {
|
|
523
|
+
void core_1.Module.resolveMime(result).then(font => {
|
|
524
|
+
if (font?.mime === mimeType) {
|
|
525
|
+
writeFont(result, font.ext, from);
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
errorResponse(font);
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
else {
|
|
533
|
+
errorResponse(null, "Worker did not finish");
|
|
534
|
+
}
|
|
447
535
|
};
|
|
448
536
|
startProcess(true);
|
|
449
|
-
void
|
|
537
|
+
void core_1.Module.resolveMime(data)
|
|
450
538
|
.then(font => {
|
|
451
539
|
switch (font?.mime) {
|
|
452
540
|
case "font/ttf":
|
|
453
541
|
if (cache) {
|
|
454
542
|
CACHE_FONTFROM[hash] = 'ttf';
|
|
455
543
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
}
|
|
544
|
+
if (this.hasPermission('worker', options) && (worker = WORKER.get('ttf').sendBuffer(data, shared, checkResult, 'ttf', "font/woff2"))) {
|
|
545
|
+
startProcess(false);
|
|
546
|
+
}
|
|
547
|
+
else {
|
|
548
|
+
startProcess(false);
|
|
549
|
+
void wawoff2.compress(data).then(result => {
|
|
550
|
+
checkResult(result, 'ttf', "font/woff2");
|
|
551
|
+
});
|
|
552
|
+
}
|
|
459
553
|
break;
|
|
460
554
|
case "font/otf":
|
|
461
555
|
if (cache) {
|
|
462
556
|
CACHE_FONTFROM[hash] = 'otf';
|
|
463
557
|
}
|
|
464
|
-
|
|
558
|
+
if (this.hasPermission('worker', options) && (worker = WORKER.get('otf').sendBuffer(data, shared, checkResult, 'otf', "font/woff"))) {
|
|
559
|
+
startProcess(false);
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
startProcess(false);
|
|
563
|
+
checkResult(toWoff(data), 'otf', "font/woff");
|
|
564
|
+
}
|
|
465
565
|
break;
|
|
466
566
|
default:
|
|
467
567
|
errorResponse(font);
|
|
@@ -472,13 +572,13 @@ class Compress extends module_1 {
|
|
|
472
572
|
break;
|
|
473
573
|
}
|
|
474
574
|
default: {
|
|
475
|
-
const compressor = this.compressors[format]
|
|
575
|
+
const compressor = this.compressors[format];
|
|
476
576
|
if (typeof compressor !== 'function') {
|
|
477
577
|
throw (0, types_1.errorValue)("Missing compression plugin", format);
|
|
478
578
|
}
|
|
479
579
|
startProcess(true);
|
|
480
580
|
if (compressor.toString().startsWith('async')) {
|
|
481
|
-
compressor.call(this,
|
|
581
|
+
compressor.call(this, data, output, options)
|
|
482
582
|
.then(result => {
|
|
483
583
|
if (typeof result === 'string') {
|
|
484
584
|
endProcess(null, null, format, result);
|
|
@@ -490,7 +590,7 @@ class Compress extends module_1 {
|
|
|
490
590
|
.catch(endProcess);
|
|
491
591
|
}
|
|
492
592
|
else {
|
|
493
|
-
void compressor.call(this,
|
|
593
|
+
void compressor.call(this, data, output, options, endProcess);
|
|
494
594
|
}
|
|
495
595
|
break;
|
|
496
596
|
}
|
|
@@ -509,7 +609,13 @@ class Compress extends module_1 {
|
|
|
509
609
|
else {
|
|
510
610
|
options ||= {};
|
|
511
611
|
}
|
|
512
|
-
const { filename, startTime = process.hrtime.bigint(), timeout = 0
|
|
612
|
+
const { filename, startTime = process.hrtime.bigint(), timeout = 0 } = options;
|
|
613
|
+
if (!(0, types_1.isString)(output)) {
|
|
614
|
+
output = typeof file === 'string' ? file : '';
|
|
615
|
+
}
|
|
616
|
+
if (output && !this.canWrite(output, { ownPermissionOnly: true })) {
|
|
617
|
+
return Promise.reject((0, types_1.errorValue)("Operation not permitted", output));
|
|
618
|
+
}
|
|
513
619
|
let plugin = options.plugin;
|
|
514
620
|
if ((0, types_1.isString)(plugin)) {
|
|
515
621
|
if (types_1.IMPORT_MAP[plugin]) {
|
|
@@ -517,18 +623,16 @@ class Compress extends module_1 {
|
|
|
517
623
|
}
|
|
518
624
|
}
|
|
519
625
|
else {
|
|
520
|
-
return Promise.reject();
|
|
521
|
-
}
|
|
522
|
-
if (!(0, types_1.isString)(output)) {
|
|
523
|
-
output = typeof file === 'string' ? file : '';
|
|
626
|
+
return Promise.reject((0, types_1.errorValue)("Missing compression plugin", output));
|
|
524
627
|
}
|
|
525
628
|
const ext = output ? path.extname(output).substring(1) : options.format || "Unknown";
|
|
526
629
|
const getFormat = () => output ? path.basename(output) : ext;
|
|
527
|
-
let data;
|
|
630
|
+
let data, shared = false;
|
|
528
631
|
if (Buffer.isBuffer(file)) {
|
|
529
632
|
data = file;
|
|
633
|
+
shared = true;
|
|
530
634
|
}
|
|
531
|
-
else {
|
|
635
|
+
else if (this.canRead(file, { ownPermissionOnly: true })) {
|
|
532
636
|
try {
|
|
533
637
|
data = fs.readFileSync(file);
|
|
534
638
|
}
|
|
@@ -536,23 +640,26 @@ class Compress extends module_1 {
|
|
|
536
640
|
return Promise.reject(err);
|
|
537
641
|
}
|
|
538
642
|
}
|
|
643
|
+
else {
|
|
644
|
+
return Promise.reject((0, types_1.errorValue)("Operation not permitted", file));
|
|
645
|
+
}
|
|
539
646
|
if (!options.mimeType) {
|
|
540
|
-
const out = await
|
|
647
|
+
const out = await core_1.Module.resolveMime(data);
|
|
541
648
|
if (out) {
|
|
542
649
|
options.mimeType = out.mime;
|
|
543
650
|
}
|
|
544
651
|
}
|
|
545
652
|
const startLength = Buffer.byteLength(data);
|
|
546
653
|
return new Promise(async (resolve, reject) => {
|
|
547
|
-
let timer = null, hash, cacheKey,
|
|
654
|
+
let timer = null, hash, cacheKey, closed = false;
|
|
548
655
|
const failed = (err) => {
|
|
549
|
-
aborted = true;
|
|
550
656
|
if (timer) {
|
|
551
657
|
clearTimeout(timer);
|
|
552
658
|
}
|
|
659
|
+
closed = true;
|
|
553
660
|
reject(err);
|
|
554
661
|
};
|
|
555
|
-
const complete = (err, result, ctime) => {
|
|
662
|
+
const complete = (err, result, worker, ctime) => {
|
|
556
663
|
if (err) {
|
|
557
664
|
reject(err);
|
|
558
665
|
return;
|
|
@@ -560,14 +667,14 @@ class Compress extends module_1 {
|
|
|
560
667
|
const value = output ? path.basename(output) : filename || (0, types_1.isString)(file) && path.basename(file);
|
|
561
668
|
const status = value ? plugin + ': ' + value : "Completed";
|
|
562
669
|
if (ctime) {
|
|
563
|
-
this.formatMessage(8, value ? path.extname(value).substring(1) : '', [status, 'cache'], ctime.toLocaleString(), { ...
|
|
670
|
+
this.formatMessage(8, value ? path.extname(value).substring(1) : '', [status, 'cache'], ctime.toLocaleString(), { ...core_1.Module.LOG_STYLE_NOTICE, hintBold: true, sessionId: options.sessionId, broadcastId: options.broadcastId });
|
|
564
671
|
}
|
|
565
672
|
else {
|
|
566
|
-
this.writeTimeProcess(ext, status + getOutputSize(startLength, result), startTime, { type: 8, sessionId, broadcastId });
|
|
673
|
+
this.writeTimeProcess(ext, status + getOutputSize(startLength, result, worker), startTime, { type: 8, sessionId: options.sessionId, broadcastId: options.broadcastId });
|
|
567
674
|
}
|
|
568
675
|
if (!ctime && hash && cacheKey && TEMP_DIR) {
|
|
569
676
|
const pathname = path.join(TEMP_DIR, sanitizePath(plugin), hash);
|
|
570
|
-
if (
|
|
677
|
+
if (core_1.Module.createDir(pathname)) {
|
|
571
678
|
fs.writeFile(path.join(pathname, cacheKey), result, error => {
|
|
572
679
|
if (!error) {
|
|
573
680
|
((CACHE_IMAGE[plugin] ||= {})[hash] ||= {})[cacheKey] = new Date();
|
|
@@ -577,8 +684,8 @@ class Compress extends module_1 {
|
|
|
577
684
|
}
|
|
578
685
|
resolve(result);
|
|
579
686
|
};
|
|
580
|
-
const success = (result, ctime) => {
|
|
581
|
-
if (
|
|
687
|
+
const success = (result, worker = false, ctime) => {
|
|
688
|
+
if (closed) {
|
|
582
689
|
return;
|
|
583
690
|
}
|
|
584
691
|
if (timer) {
|
|
@@ -586,22 +693,22 @@ class Compress extends module_1 {
|
|
|
586
693
|
}
|
|
587
694
|
if (output) {
|
|
588
695
|
fs.writeFile(output, result, err => {
|
|
589
|
-
complete(err, result, ctime);
|
|
696
|
+
complete(err, result, worker, ctime);
|
|
590
697
|
});
|
|
591
698
|
}
|
|
592
699
|
else {
|
|
593
|
-
complete(null, result, ctime);
|
|
700
|
+
complete(null, result, worker, ctime);
|
|
594
701
|
}
|
|
595
702
|
};
|
|
596
703
|
if (this.settings.cache && setCacheData(this, 1)) {
|
|
597
704
|
let stored;
|
|
598
705
|
try {
|
|
599
|
-
hash =
|
|
706
|
+
hash = core_1.Module.asHash(data);
|
|
600
707
|
stored = (CACHE_IMAGE[plugin] ||= {})[hash];
|
|
601
|
-
cacheKey = plugin + (
|
|
708
|
+
cacheKey = plugin + (options.options ? ':' + core_1.Module.asHash(core_1.Module.asString(options.options)) : '') + (options.metadata ? ':' + core_1.Module.asHash(core_1.Module.asString(options.metadata)) : '');
|
|
602
709
|
const ctime = stored?.[cacheKey];
|
|
603
710
|
if (ctime) {
|
|
604
|
-
success(fs.readFileSync(path.join(TEMP_DIR, sanitizePath(plugin), hash, cacheKey)), ctime);
|
|
711
|
+
success(fs.readFileSync(path.join(TEMP_DIR, sanitizePath(plugin), hash, cacheKey)), false, ctime);
|
|
605
712
|
return;
|
|
606
713
|
}
|
|
607
714
|
}
|
|
@@ -612,8 +719,40 @@ class Compress extends module_1 {
|
|
|
612
719
|
}
|
|
613
720
|
}
|
|
614
721
|
}
|
|
615
|
-
this.formatMessage(8, ext, ['Compressing image...', plugin], filename || output, { titleColor: 'magenta', sessionId, broadcastId });
|
|
722
|
+
this.formatMessage(8, ext, ['Compressing image...', plugin], filename || output, { titleColor: 'magenta', sessionId: options.sessionId, broadcastId: options.broadcastId });
|
|
616
723
|
try {
|
|
724
|
+
let worker = null;
|
|
725
|
+
const outData = (result) => {
|
|
726
|
+
if (result && result !== data) {
|
|
727
|
+
success(result, !!worker);
|
|
728
|
+
}
|
|
729
|
+
else {
|
|
730
|
+
failed((0, types_1.errorMessage)(plugin, "Unsupported MIME", getFormat()));
|
|
731
|
+
}
|
|
732
|
+
};
|
|
733
|
+
const startTimeout = (value, message) => {
|
|
734
|
+
if (value > 0) {
|
|
735
|
+
timer = setTimeout(() => {
|
|
736
|
+
if (worker) {
|
|
737
|
+
void worker.terminate();
|
|
738
|
+
}
|
|
739
|
+
failed((0, types_1.errorMessage)(plugin, message, options.mimeType));
|
|
740
|
+
}, value);
|
|
741
|
+
}
|
|
742
|
+
};
|
|
743
|
+
if (options.mimeType) {
|
|
744
|
+
(options.metadata ||= {}).mimeType ||= options.mimeType;
|
|
745
|
+
}
|
|
746
|
+
if (this.hasPermission('worker', options)) {
|
|
747
|
+
try {
|
|
748
|
+
if (worker = WORKER.get('image').sendObject({ plugin, data, options: options.options, metadata: options.metadata }, shared || SUPPORTED_NODE21 ? [] : [data.buffer], outData)) {
|
|
749
|
+
startTimeout(getWorkerTimeout(options, timeout), "Worker timeout was exceeded");
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
catch {
|
|
754
|
+
}
|
|
755
|
+
}
|
|
617
756
|
let transform;
|
|
618
757
|
try {
|
|
619
758
|
transform = await (0, types_1.importESM)(plugin, true);
|
|
@@ -621,35 +760,29 @@ class Compress extends module_1 {
|
|
|
621
760
|
catch {
|
|
622
761
|
transform = require(plugin);
|
|
623
762
|
}
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
failed((0, types_1.errorMessage)(plugin, "Timeout was exceeded"));
|
|
628
|
-
}, timeout);
|
|
629
|
-
}
|
|
630
|
-
void out(data).then(result => {
|
|
631
|
-
if (result !== data) {
|
|
632
|
-
success(result);
|
|
633
|
-
}
|
|
634
|
-
else {
|
|
635
|
-
failed((0, types_1.errorMessage)(plugin, "Unsupported MIME", getFormat()));
|
|
636
|
-
}
|
|
637
|
-
});
|
|
763
|
+
startTimeout(timeout, "Timeout was exceeded");
|
|
764
|
+
const out = transform.call(this, options.options, options.metadata);
|
|
765
|
+
void out(data).then(outData);
|
|
638
766
|
}
|
|
639
767
|
catch (err) {
|
|
640
768
|
failed(err);
|
|
641
769
|
}
|
|
642
770
|
});
|
|
643
771
|
}
|
|
772
|
+
hasPermission(type, options) {
|
|
773
|
+
if (super.hasPermission(type)) {
|
|
774
|
+
return type === 'worker' ? core_1.WorkerChannel.hasPermission(options) : true;
|
|
775
|
+
}
|
|
776
|
+
return false;
|
|
777
|
+
}
|
|
644
778
|
set chunkSize(value) {
|
|
645
|
-
this
|
|
779
|
+
this.#chunkSize = !isNaN(value = (0, types_1.alignSize)(value, 1)) ? value : undefined;
|
|
646
780
|
}
|
|
647
781
|
get chunkSize() {
|
|
648
|
-
return this
|
|
782
|
+
return this.#chunkSize;
|
|
649
783
|
}
|
|
650
784
|
get settings() {
|
|
651
785
|
return this.module.settings ||= {};
|
|
652
786
|
}
|
|
653
787
|
}
|
|
654
|
-
_a = kChunkSize;
|
|
655
788
|
module.exports = Compress;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e-mc/compress",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Compress constructor for E-mc.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"license": "BSD-3-Clause",
|
|
24
24
|
"homepage": "https://github.com/anpham6/e-mc#readme",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@e-mc/
|
|
27
|
-
"@e-mc/types": "0.
|
|
26
|
+
"@e-mc/core": "0.12.0",
|
|
27
|
+
"@e-mc/types": "0.12.0",
|
|
28
28
|
"wawoff2": "^2.0.1",
|
|
29
29
|
"woff2sfnt-sfnt2woff": "^1.0.0"
|
|
30
30
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const node_worker_threads_1 = require("node:worker_threads");
|
|
3
|
+
const types_1 = require("@e-mc/types");
|
|
4
|
+
const index_1 = require("@e-mc/compress");
|
|
5
|
+
const PORT = node_worker_threads_1.workerData[0];
|
|
6
|
+
node_worker_threads_1.parentPort.on('message', async (value) => {
|
|
7
|
+
try {
|
|
8
|
+
const { plugin, data, options, metadata } = value;
|
|
9
|
+
let transform;
|
|
10
|
+
try {
|
|
11
|
+
transform = await (0, types_1.importESM)(plugin, true);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
transform = require(plugin);
|
|
15
|
+
}
|
|
16
|
+
transform(options, metadata)(index_1.asBuffer(data))
|
|
17
|
+
.then(result => {
|
|
18
|
+
try {
|
|
19
|
+
PORT.postMessage(result, [result.buffer]);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
PORT.postMessage(result);
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
.catch((err) => {
|
|
26
|
+
console.error(err);
|
|
27
|
+
PORT.postMessage(null);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
console.error(err);
|
|
32
|
+
PORT.postMessage(null);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const node_worker_threads_1 = require("node:worker_threads");
|
|
3
|
+
const { toWoff } = require('woff2sfnt-sfnt2woff');
|
|
4
|
+
const PORT = node_worker_threads_1.workerData[0];
|
|
5
|
+
node_worker_threads_1.parentPort.on('message', (value) => {
|
|
6
|
+
try {
|
|
7
|
+
const data = toWoff(value);
|
|
8
|
+
PORT.postMessage(data, [data.buffer]);
|
|
9
|
+
}
|
|
10
|
+
catch (err) {
|
|
11
|
+
console.error(err);
|
|
12
|
+
PORT.postMessage(null);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const node_worker_threads_1 = require("node:worker_threads");
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const stream = require("node:stream");
|
|
5
|
+
const zlib = require("node:zlib");
|
|
6
|
+
const index_1 = require("@e-mc/compress");
|
|
7
|
+
const PORT = node_worker_threads_1.workerData[0];
|
|
8
|
+
node_worker_threads_1.parentPort.on('message', async (value) => {
|
|
9
|
+
try {
|
|
10
|
+
const { data, options, output } = value;
|
|
11
|
+
const chunks = [];
|
|
12
|
+
let transform = stream.Readable.from(index_1.asBuffer(data)).pipe(zlib.createBrotliCompress(options));
|
|
13
|
+
if (output) {
|
|
14
|
+
transform = transform.pipe(fs.createWriteStream(output));
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
transform.on('data', chunk => {
|
|
18
|
+
chunks.push(chunk);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
transform
|
|
22
|
+
.on('finish', () => {
|
|
23
|
+
if (chunks.length > 0) {
|
|
24
|
+
const result = Buffer.concat(chunks);
|
|
25
|
+
PORT.postMessage(result, [result.buffer]);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
PORT.postMessage(output || null);
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
.on('error', (err) => {
|
|
32
|
+
transform.destroy();
|
|
33
|
+
throw err;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
console.error(err);
|
|
38
|
+
PORT.postMessage(null);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const node_worker_threads_1 = require("node:worker_threads");
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const stream = require("node:stream");
|
|
5
|
+
const zlib = require("node:zlib");
|
|
6
|
+
const index_1 = require("@e-mc/compress");
|
|
7
|
+
const PORT = node_worker_threads_1.workerData[0];
|
|
8
|
+
node_worker_threads_1.parentPort.on('message', async (value) => {
|
|
9
|
+
try {
|
|
10
|
+
const { data, options, output } = value;
|
|
11
|
+
const chunks = [];
|
|
12
|
+
let transform = stream.Readable.from(index_1.asBuffer(data)).pipe(zlib.createGzip(options));
|
|
13
|
+
if (output) {
|
|
14
|
+
transform = transform.pipe(fs.createWriteStream(output));
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
transform.on('data', chunk => {
|
|
18
|
+
chunks.push(chunk);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
transform
|
|
22
|
+
.on('finish', () => {
|
|
23
|
+
if (chunks.length > 0) {
|
|
24
|
+
const result = Buffer.concat(chunks);
|
|
25
|
+
PORT.postMessage(result, [result.buffer]);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
PORT.postMessage(output || null);
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
.on('error', (err) => {
|
|
32
|
+
transform.destroy();
|
|
33
|
+
throw err;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
console.error(err);
|
|
38
|
+
PORT.postMessage(null);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const node_worker_threads_1 = require("node:worker_threads");
|
|
3
|
+
const wawoff2 = require("wawoff2");
|
|
4
|
+
const PORT = node_worker_threads_1.workerData[0];
|
|
5
|
+
node_worker_threads_1.parentPort.on('message', (value) => {
|
|
6
|
+
wawoff2.compress(value)
|
|
7
|
+
.then(data => {
|
|
8
|
+
PORT.postMessage(data);
|
|
9
|
+
})
|
|
10
|
+
.catch((err) => {
|
|
11
|
+
console.error(err);
|
|
12
|
+
PORT.postMessage(null);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const node_worker_threads_1 = require("node:worker_threads");
|
|
3
|
+
const wawoff2 = require("wawoff2");
|
|
4
|
+
const PORT = node_worker_threads_1.workerData[0];
|
|
5
|
+
node_worker_threads_1.parentPort.on('message', (value) => {
|
|
6
|
+
wawoff2.decompress(value)
|
|
7
|
+
.then(data => {
|
|
8
|
+
PORT.postMessage(data);
|
|
9
|
+
})
|
|
10
|
+
.catch((err) => {
|
|
11
|
+
console.error(err);
|
|
12
|
+
PORT.postMessage(null);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const node_worker_threads_1 = require("node:worker_threads");
|
|
3
|
+
const { toSfnt } = require('woff2sfnt-sfnt2woff');
|
|
4
|
+
const PORT = node_worker_threads_1.workerData[0];
|
|
5
|
+
node_worker_threads_1.parentPort.on('message', (value) => {
|
|
6
|
+
try {
|
|
7
|
+
const data = toSfnt(value);
|
|
8
|
+
PORT.postMessage(data, [data.buffer]);
|
|
9
|
+
}
|
|
10
|
+
catch (err) {
|
|
11
|
+
console.error(err);
|
|
12
|
+
PORT.postMessage(null);
|
|
13
|
+
}
|
|
14
|
+
});
|