From f71c893f634df73c097917a07a2892bb2001fc7f Mon Sep 17 00:00:00 2001 From: Jeff Schiller Date: Mon, 11 Dec 2023 22:00:35 -0800 Subject: [PATCH] Fix issue #44, make decompress work in NodeJS (use Worker only where possible). --- CHANGELOG.md | 6 ++++++ README.md | 34 +++++++++++++++++++++++------ archive/decompress-internal.js | 13 +++-------- archive/decompress.js | 36 +++++++++++++++++-------------- package.json | 2 +- types/archive/decompress.d.ts.map | 2 +- 6 files changed, 59 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8be96cd..6c0be3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. +## [1.1.7] - 2023-12-11 + +### Changed + +- decompress: Allow unarchiving in Node. + ## [1.1.6] - 2023-10-25 ### Changed diff --git a/README.md b/README.md index 70c00fb..555eec3 100644 --- a/README.md +++ b/README.md @@ -6,21 +6,25 @@ A set of dependency-free JavaScript modules to handle binary data in JS (using Typed Arrays). Includes: - * bitjs/archive: Unarchiving files (unzip, unrar, untar) in the browser, implemented as Web Workers and allowing progressively unarchiving while streaming. - * bitjs/codecs: Get the codec info of media containers in a ISO RFC6381 MIME type string + * bitjs/archive: Unarchiving files (unzip, unrar, untar) in JavaScript, + implemented as Web Workers where supported, and allowing progressive + unarchiving while streaming. + * bitjs/codecs: Get the codec info of media containers in a ISO RFC6381 + MIME type string * bitjs/file: Detect the type of file from its binary signature. * bitjs/image: Conversion of WebP images to PNG or JPEG. - * bitjs/io: Low-level classes for interpreting binary data (BitStream, ByteStream). For example, reading or peeking at N bits at a time. + * bitjs/io: Low-level classes for interpreting binary data (BitStream + ByteStream). For example, reading or peeking at N bits at a time. ## Installation Install it using your favourite package manager, the package is registered under `@codedread/bitjs`. ```bash -$ npm install @codedread/bitjs +npm install @codedread/bitjs ``` or ```bash -$ yarn add @codedread/bitjs +yarn add @codedread/bitjs ``` ### Using in Node @@ -44,7 +48,7 @@ const { getFullMIMEString } = await import('@codedread/bitjs'); ### bitjs.archive -This package includes objects for unarchiving binary data in popular archive formats (zip, rar, tar) providing unzip, unrar and untar capabilities via JavaScript in the browser. A prototype version of a compressor that creates Zip files is also present. The decompression/compression actually happens inside a Web Worker. +This package includes objects for unarchiving binary data in popular archive formats (zip, rar, tar) providing unzip, unrar and untar capabilities via JavaScript in the browser. A prototype version of a compressor that creates Zip files is also present. The decompression/compression actually happens inside a Web Worker, when the runtime supports it (browsers, deno). #### Decompressing @@ -88,6 +92,24 @@ unzipper.update(anArrayBufferWithMoreBytes); unzipper.update(anArrayBufferWithYetMoreBytes); ``` +##### A NodeJS Example + +```javascript + import * as fs from 'fs'; + import { getUnarchiver } from './archive/decompress.js'; + + const nodeBuffer = fs.readFileSync('comic.cbz'); + const ab = nodeBuffer.buffer.slice(nodeBuffer.byteOffset, nodeBuffer.byteOffset + nodeBuffer.length); + const unarchiver = getUnarchiver(ab, { pathToBitJS: './' }); + unarchiver.addEventListener('progress', () => process.stdout.write('.')); + unarchiver.addEventListener('extract', (evt) => { + const extractedFile = evt.unarchivedFile; + console.log(`${extractedFile.filename} (${extractedFile.fileData.byteLength} bytes)`); + }); + unarchiver.addEventListener('finish', () => console.log(`Done!`)); + unarchiver.start(); +``` + #### Compressing The Zipper only supports creating zip files without compression (store only) for now. The interface diff --git a/archive/decompress-internal.js b/archive/decompress-internal.js index 3fb8d38..299ab03 100644 --- a/archive/decompress-internal.js +++ b/archive/decompress-internal.js @@ -20,13 +20,6 @@ import { findMimeType } from '../file/sniffer.js'; * @property {Uint8Array} fileData */ -/** - * An enum for threading mode. Currently supporting only WebWorkers. - */ -export const ThreadingMode = { - WEB_WORKER: 'WEB_WORKER', -} - /** * @typedef UnarchiverOptions * @property {string} pathToBitJS The path to the bitjs folder. @@ -232,7 +225,7 @@ export class UnzipperInternal extends Unarchiver { } getMIMEType() { return 'application/zip'; } - getScriptFileName() { return 'archive/unzip.js'; } + getScriptFileName() { return './unzip.js'; } } export class UnrarrerInternal extends Unarchiver { @@ -241,7 +234,7 @@ export class UnrarrerInternal extends Unarchiver { } getMIMEType() { return 'application/x-rar-compressed'; } - getScriptFileName() { return 'archive/unrar.js'; } + getScriptFileName() { return './unrar.js'; } } export class UntarrerInternal extends Unarchiver { @@ -250,7 +243,7 @@ export class UntarrerInternal extends Unarchiver { } getMIMEType() { return 'application/x-tar'; } - getScriptFileName() { return 'archive/untar.js'; }; + getScriptFileName() { return './untar.js'; }; } /** diff --git a/archive/decompress.js b/archive/decompress.js index ebed8ad..b4e07f2 100644 --- a/archive/decompress.js +++ b/archive/decompress.js @@ -28,9 +28,9 @@ export { } /** -* All extracted files returned by an Unarchiver will implement -* the following interface: -*/ + * All extracted files returned by an Unarchiver will implement + * the following interface: + */ /** * @typedef UnarchivedFile @@ -43,23 +43,27 @@ export { */ /** - * Creates a WebWorker with the given decompressor implementation (e.g. unzip.js) - * and transfers a MessagePort for communication. Returns a Promise to the Worker. + * Connects the MessagePort to the unarchiver implementation (e.g. unzip.js). If Workers exist + * (e.g. web browsers or deno), imports the implementation inside a Web Worker. Otherwise, it + * dynamically imports the implementation inside the current JS context. + * The MessagePort is used for communication between host and implementation. * @param {string} pathToBitJS The path to the bitjs folder. - * @param {string} implFilename The decompressor implementation filename - * relative to this path (e.g. './unzip.js'). - * @param {MessagePort} implPort The MessagePort to connect to the decompressor - * implementation. - * @returns {Promise<*>} Returns a Promise that resolves to the Worker object. + * @param {string} implFilename The decompressor implementation filename relative to this path + * (e.g. './unzip.js'). + * @param {MessagePort} implPort The MessagePort to connect to the decompressor implementation. + * @returns {Promise} The Promise resolves once the ports are connected. */ -const connectPortFn = (pathToBitJS, implFilename, implPort) => { - return new Promise((resolve, reject) => { - const worker = new Worker(pathToBitJS + 'archive/unarchiver-webworker.js', { - type: 'module' +const connectPortFn = async (pathToBitJS, implFilename, implPort) => { + if (typeof Worker === 'undefined') { + return import(`${implFilename}`).then(implModule => { + implModule.connect(implPort) }); + } - worker.postMessage({ implSrc: (pathToBitJS + implFilename), }, [implPort]); - resolve(worker); + return new Promise((resolve, reject) => { + const worker = new Worker(pathToBitJS + 'archive/unarchiver-webworker.js', { type: 'module' }); + worker.postMessage({ implSrc: implFilename }, [implPort]); + resolve(); }); }; diff --git a/package.json b/package.json index ebeaef2..879d759 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@codedread/bitjs", - "version": "1.1.6", + "version": "1.1.7", "description": "Binary Tools for JavaScript", "homepage": "https://github.com/codedread/bitjs", "author": "Jeff Schiller", diff --git a/types/archive/decompress.d.ts.map b/types/archive/decompress.d.ts.map index ca3a36a..2ff5100 100644 --- a/types/archive/decompress.d.ts.map +++ b/types/archive/decompress.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"decompress.d.ts","sourceRoot":"","sources":["../../archive/decompress.js"],"names":[],"mappings":"AAgFA;;;;;;;;;;EAUE;AACF,kCARU,WAAW,YAGX,iBAAiB,GAAC,MAAM,GAGtB,UAAU,CAIrB;AAzBD;IACE,mCAA+D;CAChE;AAED;IACE,mCAA+D;CAChE;AAED;IACE,mCAA+D;CAChE;;cAzCa,MAAM;cACN,UAAU;;gCAIX,OAAO,0BAA0B,EAAE,iBAAiB"} \ No newline at end of file +{"version":3,"file":"decompress.d.ts","sourceRoot":"","sources":["../../archive/decompress.js"],"names":[],"mappings":"AAmFA;;;;;;;;;;EAUE;AACF,kCARU,WAAW,YAGX,iBAAiB,GAAC,MAAM,GAGtB,UAAU,CAIrB;AAzBD;IACE,mCAA+D;CAChE;AAED;IACE,mCAA+D;CAChE;AAED;IACE,mCAA+D;CAChE;;cA7Ca,MAAM;cACN,UAAU;;gCAIX,OAAO,0BAA0B,EAAE,iBAAiB"} \ No newline at end of file