|
11 | 11 | * DEFLATE format: http://tools.ietf.org/html/rfc1951 |
12 | 12 | */ |
13 | 13 |
|
14 | | -// This file expects to be invoked as a Worker (see onmessage below). |
15 | 14 | import { ByteBuffer } from '../io/bytebuffer.js'; |
16 | 15 |
|
| 16 | +/** @type {MessagePort} */ |
| 17 | +let hostPort; |
| 18 | + |
17 | 19 | /** |
18 | | - * The client sends messages to this Worker containing files to archive in order. The client |
19 | | - * indicates to the Worker when the last file has been sent to be compressed. |
| 20 | + * The client sends a set of CompressFilesMessage to the MessagePort containing files to archive in |
| 21 | + * order. The client sets isLastFile to true to indicate to the implementation when the last file |
| 22 | + * has been sent to be compressed. |
20 | 23 | * |
21 | | - * The Worker emits an event to indicate compression has started: { type: 'start' } |
22 | | - * As the files compress, bytes are sent back in order: { type: 'compress', bytes: Uint8Array } |
23 | | - * After the last file compresses, the Worker indicates finish by: { type 'finish' } |
| 24 | + * The impl posts an event to the port indicating compression has started: { type: 'start' }. |
| 25 | + * As each file compresses, bytes are sent back in order: { type: 'compress', bytes: Uint8Array }. |
| 26 | + * After the last file compresses, we indicate finish by: { type 'finish' } |
24 | 27 | * |
25 | | - * Clients should append the bytes to a single buffer in the order they were received. |
| 28 | + * The client should append the bytes to a single buffer in the order they were received. |
26 | 29 | */ |
27 | 30 |
|
| 31 | +// TODO(bitjs): De-dupe this typedef and the one in compress.js. |
28 | 32 | /** |
29 | | - * @typedef FileInfo An object that is sent to this worker by the client to represent a file. |
| 33 | + * @typedef FileInfo An object that is sent by the client to represent a file. |
30 | 34 | * @property {string} fileName The name of this file. TODO: Includes the path? |
31 | 35 | * @property {number} lastModTime The number of ms since the Unix epoch (1970-01-01 at midnight). |
32 | 36 | * @property {Uint8Array} fileData The raw bytes of the file. |
33 | 37 | */ |
34 | 38 |
|
35 | | -// TODO: Support DEFLATE. |
36 | | -// TODO: Support options that can let client choose levels of compression/performance. |
37 | | - |
| 39 | +// TODO(bitjs): Figure out where this typedef should live. |
38 | 40 | /** |
39 | | - * Ideally these constants should be defined in a common isomorphic ES module. Unfortunately, the |
40 | | - * state of JavaScript is such that modules cannot be shared easily across browsers, worker threads, |
41 | | - * NodeJS environments, etc yet. Thus, these constants, as well as logic that should be extracted to |
42 | | - * common modules and shared with unzip.js are not yet easily possible. |
| 41 | + * @typedef CompressFilesMessage A message the client sends to the implementation. |
| 42 | + * @property {FileInfo[]} files A set of files to add to the zip file. |
| 43 | + * @property {boolean} isLastFile Indicates this is the last set of files to add to the zip file. |
43 | 44 | */ |
44 | 45 |
|
| 46 | +// TODO: Support DEFLATE. |
| 47 | +// TODO: Support options that can let client choose levels of compression/performance. |
| 48 | + |
| 49 | +// TODO(bitjs): These constants should be defined in a common isomorphic ES module. |
45 | 50 | const zLocalFileHeaderSignature = 0x04034b50; |
46 | 51 | const zCentralFileHeaderSignature = 0x02014b50; |
47 | 52 | const zEndOfCentralDirSignature = 0x06054b50; |
@@ -231,39 +236,52 @@ function writeCentralFileDirectory() { |
231 | 236 | } |
232 | 237 |
|
233 | 238 | /** |
234 | | - * @param {{data: {isLastFile?: boolean, files: FileInfo[]}}} evt The event for the Worker |
235 | | - * to process. It is an error to send any more events to the Worker if a previous event had |
236 | | - * isLastFile is set to true. |
| 239 | + * @param {{data: CompressFilesMessage}} evt The event for the implementation to process. It is an |
| 240 | + * error to send any more events after a previous event had isLastFile is set to true. |
237 | 241 | */ |
238 | | -onmessage = function(evt) { |
| 242 | +const onmessage = function(evt) { |
239 | 243 | if (state === CompressorState.FINISHED) { |
240 | | - throw `The zip worker was sent a message after last file received.`; |
| 244 | + throw `The zip implementation was sent a message after last file received.`; |
241 | 245 | } |
242 | 246 |
|
243 | 247 | if (state === CompressorState.NOT_STARTED) { |
244 | | - postMessage({ type: 'start' }); |
| 248 | + hostPort.postMessage({ type: 'start' }); |
245 | 249 | } |
246 | 250 |
|
247 | 251 | state = CompressorState.COMPRESSING; |
248 | 252 |
|
249 | | - /** @type {FileInfo[]} */ |
250 | | - const filesToCompress = evt.data.files; |
| 253 | + const msg = evt.data; |
| 254 | + const filesToCompress = msg.files; |
251 | 255 | while (filesToCompress.length > 0) { |
252 | 256 | const fileInfo = filesToCompress.shift(); |
253 | 257 | const fileBuffer = zipOneFile(fileInfo); |
254 | 258 | filesCompressed.push(fileInfo); |
255 | 259 | numBytesWritten += fileBuffer.data.byteLength; |
256 | | - this.postMessage({ type: 'compress', bytes: fileBuffer.data }, [ fileBuffer.data.buffer ]); |
| 260 | + hostPort.postMessage({ type: 'compress', bytes: fileBuffer.data }, [ fileBuffer.data.buffer ]); |
257 | 261 | } |
258 | 262 |
|
259 | 263 | if (evt.data.isLastFile) { |
260 | 264 | const centralBuffer = writeCentralFileDirectory(); |
261 | 265 | numBytesWritten += centralBuffer.data.byteLength; |
262 | | - this.postMessage({ type: 'compress', bytes: centralBuffer.data }, [ centralBuffer.data.buffer ]); |
| 266 | + hostPort.postMessage({ type: 'compress', bytes: centralBuffer.data }, |
| 267 | + [ centralBuffer.data.buffer ]); |
263 | 268 |
|
264 | 269 | state = CompressorState.FINISHED; |
265 | | - this.postMessage({ type: 'finish' }); |
| 270 | + hostPort.postMessage({ type: 'finish' }); |
266 | 271 | } else { |
267 | 272 | state = CompressorState.WAITING; |
268 | 273 | } |
269 | 274 | }; |
| 275 | + |
| 276 | + |
| 277 | +/** |
| 278 | + * Connect the host to the zip implementation with the given MessagePort. |
| 279 | + * @param {MessagePort} port |
| 280 | + */ |
| 281 | +export function connect(port) { |
| 282 | + if (hostPort) { |
| 283 | + throw `hostPort already connected`; |
| 284 | + } |
| 285 | + hostPort = port; |
| 286 | + port.onmessage = onmessage; |
| 287 | +} |
0 commit comments