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) => {
return Bluebird.try(() => {
const type = utils.getArchiveMimeType(file);
return utils.getArchiveMimeType(file).then((type) => {
if (!_.has(handlers, type)) {
throw errors.createUserError('Invalid image', `The ${type} format is not supported`);
}

View File

@ -17,7 +17,8 @@
'use strict';
const _ = require('lodash');
const readChunk = require('read-chunk');
const Bluebird = require('bluebird');
const fs = Bluebird.promisifyAll(require('fs'));
const archiveType = require('archive-type');
/**
@ -26,18 +27,34 @@ const archiveType = require('archive-type');
* @public
*
* @param {String} file - file path
* @returns {String} mime type
* @fulfil {String} - mime type
* @returns {Promise}
*
* @example
* utils.getArchiveMimeType('path/to/raspberrypi.img.gz');
* utils.getArchiveMimeType('path/to/raspberrypi.img.gz').then((mimeType) => {
* console.log(mimeType);
* });
*/
exports.getArchiveMimeType = (file) => {
// `archive-type` only needs the first 261 bytes
// See https://github.com/kevva/archive-type
const MAGIC_NUMBER_BUFFER_START = 0;
const MAGIC_NUMBER_BUFFER_END = 261;
const chunk = readChunk.sync(file, MAGIC_NUMBER_BUFFER_START, MAGIC_NUMBER_BUFFER_END);
const ARCHIVE_TYPE_IDENTIFICATION_BYTES_LENGTH = 261;
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",
"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": {
"version": "2.0.0",
"from": "read-only-stream@>=2.0.0 <3.0.0",

View File

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

View File

@ -25,29 +25,44 @@ describe('ImageStream: Utils', 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');
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');
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');
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');
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');
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);
});
});