Skip to content

Commit 2887cc1

Browse files
committed
(broken) native streams
problem: jszip assumes we have a way to syncronously finish these in end() and flush(). we don't...
1 parent 825e737 commit 2887cc1

File tree

1 file changed

+109
-17
lines changed

1 file changed

+109
-17
lines changed

lib/flate.js

Lines changed: 109 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,39 @@
11
"use strict";
22
var USE_TYPEDARRAY = (typeof Uint8Array !== "undefined") && (typeof Uint16Array !== "undefined") && (typeof Uint32Array !== "undefined");
33

4-
var pako = require("pako");
54
var utils = require("./utils");
65
var GenericWorker = require("./stream/GenericWorker");
76

87
var ARRAY_TYPE = USE_TYPEDARRAY ? "uint8array" : "array";
98

109
exports.magic = "\x08\x00";
1110

11+
/* globals CompressionStream, DecompressionStream */
12+
13+
/**
14+
* @typedef {'Deflate'|'Inflate'} Action
15+
*/
16+
1217
/**
1318
* Create a worker that uses pako to inflate/deflate.
1419
* @constructor
15-
* @param {String} action the name of the pako function to call : either "Deflate" or "Inflate".
20+
* @param {Action} action the name of the pako function to call : either "Deflate" or "Inflate".
1621
* @param {Object} options the options to use when (de)compressing.
1722
*/
1823
function FlateWorker(action, options) {
1924
GenericWorker.call(this, "FlateWorker/" + action);
2025

26+
this._initialized = false;
27+
/** @type {Action} */
28+
this._action = action;
29+
this._options = options;
30+
31+
this._stream = null;
32+
this._streamWriter = null;
2133
this._pako = null;
22-
this._pakoAction = action;
23-
this._pakoOptions = options;
34+
35+
this._handleStreamError = this._handleStreamError.bind(this);
36+
2437
// the `meta` object from the last chunk received
2538
// this allow this worker to pass around metadata
2639
this.meta = {};
@@ -33,21 +46,45 @@ utils.inherits(FlateWorker, GenericWorker);
3346
*/
3447
FlateWorker.prototype.processChunk = function (chunk) {
3548
this.meta = chunk.meta;
36-
if (this._pako === null) {
37-
this._createPako();
49+
50+
if (!this._initialized) {
51+
this._initialize();
52+
}
53+
54+
console.log("Writing", chunk);
55+
56+
if (this._streamWriter) {
57+
this._streamWriter
58+
.write(utils.transformTo(ARRAY_TYPE, chunk.data))
59+
.catch(this._handleStreamError);
60+
} else if (this._pako) {
61+
this._pako.push(utils.transformTo(ARRAY_TYPE, chunk.data), false);
62+
} else {
63+
throw new Error("processChunk() object missing");
3864
}
39-
this._pako.push(utils.transformTo(ARRAY_TYPE, chunk.data), false);
4065
};
4166

4267
/**
4368
* @see GenericWorker.flush
4469
*/
4570
FlateWorker.prototype.flush = function () {
4671
GenericWorker.prototype.flush.call(this);
47-
if (this._pako === null) {
48-
this._createPako();
72+
73+
console.log("Flushing");
74+
75+
if (!this._initialized) {
76+
this._initialize();
77+
}
78+
79+
if (this._streamWriter) {
80+
this._streamWriter
81+
.close()
82+
.catch(this._handleStreamError);
83+
} else if (this._pako) {
84+
this._pako.push([], true);
85+
} else {
86+
throw new Error("flush() object missing");
4987
}
50-
this._pako.push([], true);
5188
};
5289
/**
5390
* @see GenericWorker.cleanUp
@@ -58,19 +95,74 @@ FlateWorker.prototype.cleanUp = function () {
5895
};
5996

6097
/**
61-
* Create the _pako object.
62-
* TODO: lazy-loading this object isn't the best solution but it's the
63-
* quickest. The best solution is to lazy-load the worker list. See also the
64-
* issue #446.
98+
* Initialize worker using the best available underlying API.
6599
*/
66-
FlateWorker.prototype._createPako = function () {
67-
this._pako = new pako[this._pakoAction]({
100+
FlateWorker.prototype._initialize = function () {
101+
try {
102+
this._initializeStream();
103+
} catch (error) {
104+
// Streams not supported. Fall back to pure JS implementation.
105+
this._initializePako();
106+
}
107+
108+
this._initialized = true;
109+
};
110+
111+
/**
112+
* Initialize worker using native compression or decompression stream.
113+
*/
114+
FlateWorker.prototype._initializeStream = function () {
115+
if (this._action === "Deflate") {
116+
this._stream = new CompressionStream("deflate-raw");
117+
} else if (this._action === "Inflate") {
118+
this._stream = new DecompressionStream("deflate-raw");
119+
} else {
120+
throw new Error(`Invalid action: ${this._action}`);
121+
}
122+
123+
const reader = this._stream.readable.getReader();
124+
const writer = this._stream.writable.getWriter();
125+
this._streamWriter = writer;
126+
127+
const handleSuccess = data => {
128+
if (!data.done) {
129+
console.log("Received", data.value);
130+
131+
this.push({
132+
data: data.value,
133+
meta: this.meta
134+
});
135+
136+
reader.read().then(handleSuccess, this._handleStreamError);
137+
} else {
138+
console.log("Received done");
139+
}
140+
};
141+
142+
reader.read().then(handleSuccess, this._handleStreamError);
143+
};
144+
145+
/**
146+
* Handle errors while using the native stream.
147+
*/
148+
FlateWorker.prototype._handleStreamError = function (error) {
149+
console.error('XXX', error);
150+
};
151+
152+
/**
153+
* Initialize worker using JavaScript pako implementation.
154+
*/
155+
FlateWorker.prototype._initializePako = function () {
156+
var pako = require("pako");
157+
this._pako = new pako[this._action]({
68158
chunkSize: 65536,
69159
raw: true,
70-
level: this._pakoOptions.level || -1 // default compression
160+
level: this._options.level || -1 // default compression
71161
});
72162
var self = this;
73163
this._pako.onData = function(data) {
164+
console.log("Received", data);
165+
74166
self.push({
75167
data : data,
76168
meta : self.meta

0 commit comments

Comments
 (0)