refactor(image-stream): get rid of read-chunk (#1243)

We also took the opportunity to make `utils.getArchiveMimeType()`
asynchronous.

Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This commit is contained in:
Juan Cruz Viotti 2017-04-01 14:47:14 -04:00 committed by GitHub
parent d5ec71c5da
commit 4a3a123f42
5 changed files with 50 additions and 26 deletions

View File

@ -67,9 +67,7 @@ const errors = require('../shared/errors');
* }); * });
*/ */
exports.getFromFilePath = (file) => { exports.getFromFilePath = (file) => {
return Bluebird.try(() => { return utils.getArchiveMimeType(file).then((type) => {
const type = utils.getArchiveMimeType(file);
if (!_.has(handlers, type)) { if (!_.has(handlers, type)) {
throw errors.createUserError('Invalid image', `The ${type} format is not supported`); throw errors.createUserError('Invalid image', `The ${type} format is not supported`);
} }

View File

@ -17,7 +17,8 @@
'use strict'; 'use strict';
const _ = require('lodash'); const _ = require('lodash');
const readChunk = require('read-chunk'); const Bluebird = require('bluebird');
const fs = Bluebird.promisifyAll(require('fs'));
const archiveType = require('archive-type'); const archiveType = require('archive-type');
/** /**
@ -26,18 +27,34 @@ const archiveType = require('archive-type');
* @public * @public
* *
* @param {String} file - file path * @param {String} file - file path
* @returns {String} mime type * @fulfil {String} - mime type
* @returns {Promise}
* *
* @example * @example
* utils.getArchiveMimeType('path/to/raspberrypi.img.gz'); * utils.getArchiveMimeType('path/to/raspberrypi.img.gz').then((mimeType) => {
* console.log(mimeType);
* });
*/ */
exports.getArchiveMimeType = (file) => { exports.getArchiveMimeType = (file) => {
// `archive-type` only needs the first 261 bytes // `archive-type` only needs the first 261 bytes
// See https://github.com/kevva/archive-type // See https://github.com/kevva/archive-type
const MAGIC_NUMBER_BUFFER_START = 0; const ARCHIVE_TYPE_IDENTIFICATION_BYTES_LENGTH = 261;
const MAGIC_NUMBER_BUFFER_END = 261;
const chunk = readChunk.sync(file, MAGIC_NUMBER_BUFFER_START, MAGIC_NUMBER_BUFFER_END);
return _.get(archiveType(chunk), [ 'mime' ], 'application/octet-stream'); return Bluebird.using(fs.openAsync(file, 'r').disposer((fileDescriptor) => {
return fs.closeAsync(fileDescriptor);
}), (fileDescriptor) => {
const BUFFER_START = 0;
const chunk = new Buffer(ARCHIVE_TYPE_IDENTIFICATION_BYTES_LENGTH);
return fs.readAsync(
fileDescriptor,
chunk,
BUFFER_START,
ARCHIVE_TYPE_IDENTIFICATION_BYTES_LENGTH,
null
).then(() => {
return _.get(archiveType(chunk), [ 'mime' ], 'application/octet-stream');
});
});
}; };

5
npm-shrinkwrap.json generated
View File

@ -5521,11 +5521,6 @@
"resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
"dev": true "dev": true
}, },
"read-chunk": {
"version": "2.0.0",
"from": "read-chunk@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.0.0.tgz"
},
"read-only-stream": { "read-only-stream": {
"version": "2.0.0", "version": "2.0.0",
"from": "read-only-stream@>=2.0.0 <3.0.0", "from": "read-only-stream@>=2.0.0 <3.0.0",

View File

@ -90,7 +90,6 @@
"node-ipc": "^8.9.2", "node-ipc": "^8.9.2",
"node-stream-zip": "^1.3.4", "node-stream-zip": "^1.3.4",
"path-is-inside": "^1.0.2", "path-is-inside": "^1.0.2",
"read-chunk": "^2.0.0",
"redux": "^3.5.2", "redux": "^3.5.2",
"redux-localstorage": "^0.4.1", "redux-localstorage": "^0.4.1",
"resin-cli-form": "^1.4.1", "resin-cli-form": "^1.4.1",

View File

@ -25,29 +25,44 @@ describe('ImageStream: Utils', function() {
describe('.getArchiveMimeType()', function() { describe('.getArchiveMimeType()', function() {
it('should return application/x-bzip2 for a bz2 archive', function() { it('should resolve application/x-bzip2 for a bz2 archive', function(done) {
const file = path.join(DATA_PATH, 'bz2', 'raspberrypi.img.bz2'); const file = path.join(DATA_PATH, 'bz2', 'raspberrypi.img.bz2');
m.chai.expect(utils.getArchiveMimeType(file)).to.equal('application/x-bzip2'); utils.getArchiveMimeType(file).then((type) => {
m.chai.expect(type).to.equal('application/x-bzip2');
done();
}).catch(done);
}); });
it('should return application/x-xz for a xz archive', function() { it('should resolve application/x-xz for a xz archive', function(done) {
const file = path.join(DATA_PATH, 'xz', 'raspberrypi.img.xz'); const file = path.join(DATA_PATH, 'xz', 'raspberrypi.img.xz');
m.chai.expect(utils.getArchiveMimeType(file)).to.equal('application/x-xz'); utils.getArchiveMimeType(file).then((type) => {
m.chai.expect(type).to.equal('application/x-xz');
done();
}).catch(done);
}); });
it('should return application/gzip for a gz archive', function() { it('should resolve application/gzip for a gz archive', function(done) {
const file = path.join(DATA_PATH, 'gz', 'raspberrypi.img.gz'); const file = path.join(DATA_PATH, 'gz', 'raspberrypi.img.gz');
m.chai.expect(utils.getArchiveMimeType(file)).to.equal('application/gzip'); utils.getArchiveMimeType(file).then((type) => {
m.chai.expect(type).to.equal('application/gzip');
done();
}).catch(done);
}); });
it('should return application/zip for a zip archive', function() { it('should resolve application/zip for a zip archive', function(done) {
const file = path.join(DATA_PATH, 'zip', 'zip-directory-rpi-only.zip'); const file = path.join(DATA_PATH, 'zip', 'zip-directory-rpi-only.zip');
m.chai.expect(utils.getArchiveMimeType(file)).to.equal('application/zip'); utils.getArchiveMimeType(file).then((type) => {
m.chai.expect(type).to.equal('application/zip');
done();
}).catch(done);
}); });
it('should return application/octet-stream for an uncompress image', function() { it('should resolve application/octet-stream for an uncompress image', function(done) {
const file = path.join(DATA_PATH, 'images', 'raspberrypi.img'); const file = path.join(DATA_PATH, 'images', 'raspberrypi.img');
m.chai.expect(utils.getArchiveMimeType(file)).to.equal('application/octet-stream'); utils.getArchiveMimeType(file).then((type) => {
m.chai.expect(type).to.equal('application/octet-stream');
done();
}).catch(done);
}); });
}); });