From 461ca3ca72f821552209d767d1b41846078ccdd8 Mon Sep 17 00:00:00 2001 From: busticated Date: Thu, 30 Jan 2020 17:52:57 -0800 Subject: [PATCH 1/2] base agent can optionally return raw req object --- src/Agent.js | 26 ++++++++++++++++++++------ test/Agent.spec.js | 6 ++++-- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/Agent.js b/src/Agent.js index 04b5620..d5af047 100644 --- a/src/Agent.js +++ b/src/Agent.js @@ -59,9 +59,19 @@ export default class Agent { * @parma {Object} context the invocation context, describing the tool and project. * @return {Promise} A promise. fulfilled with {body, statusCode}, rejected with { statusCode, errorDescription, error, body } */ - request({ uri, method, data = undefined, auth, query = undefined, form = undefined, files = undefined, context = undefined }) { + request({ + uri, + method, + data = undefined, + auth, + query = undefined, + form = undefined, + files = undefined, + context = undefined, + raw = false + }) { const requestFiles = this._sanitizeFiles(files); - return this._request({ uri, method, data, auth, query, form, context, files: requestFiles }); + return this._request({ uri, method, data, auth, query, form, context, files: requestFiles, raw }); } /** @@ -76,8 +86,12 @@ export default class Agent { * @param {Object} context the invocation context * @return {Promise} A promise. fulfilled with {body, statusCode}, rejected with { statusCode, errorDescription, error, body } */ - _request({ uri, method, data, auth, query, form, files, context }) { + _request({ uri, method, data, auth, query, form, files, context, raw }) { const req = this._buildRequest({ uri, method, data, auth, query, form, context, files }); + + if (raw){ + return req; + } return this._promiseResponse(req); } @@ -123,7 +137,7 @@ export default class Agent { }); } - _buildRequest({ uri, method, data, auth, query, form, files, context, makerequest=request }) { + _buildRequest({ uri, method, data, auth, query, form, files, context, makerequest = request }) { const req = makerequest(method, uri); if (this.prefix) { req.use(this.prefix); @@ -141,7 +155,7 @@ export default class Agent { let options = { filepath: file.path }; - if (this._inBrowser(makerequest)) { + if (this.isForBrowser(makerequest)) { options = file.path; } req.attach(name, file.data, options); @@ -160,7 +174,7 @@ export default class Agent { return req; } - _inBrowser(makerequest) { + isForBrowser(makerequest = request) { // superagent only has the getXHR method in the browser version return !!makerequest.getXHR; } diff --git a/test/Agent.spec.js b/test/Agent.spec.js index 1905ceb..48439b7 100644 --- a/test/Agent.spec.js +++ b/test/Agent.spec.js @@ -304,7 +304,8 @@ describe('Agent', () => { query: 'all', form:form, files: sanitizedFiles, - context: undefined + context: undefined, + raw: false }); }); @@ -323,7 +324,8 @@ describe('Agent', () => { files: undefined, form: undefined, query: undefined, - context: undefined + context: undefined, + raw: false }); }); From 2dd6a631c0ebc6949ac36450fe32552e8d155119 Mon Sep 17 00:00:00 2001 From: busticated Date: Thu, 30 Jan 2020 17:56:15 -0800 Subject: [PATCH 2/2] overhaul broken file download methods - fixes #110 --- src/Particle.js | 52 +++++++++++++++++++++++++------------------ test/Particle.spec.js | 44 +++++++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 23 deletions(-) diff --git a/src/Particle.js b/src/Particle.js index 15fce1b..be963db 100644 --- a/src/Particle.js +++ b/src/Particle.js @@ -1,4 +1,3 @@ -import request from 'superagent'; import binaryParser from './superagent-binary-parser'; import Defaults from './Defaults'; import EventStream from './EventStream'; @@ -588,11 +587,14 @@ class Particle { * @returns {Request} A promise */ downloadFirmwareBinary({ binaryId, auth }){ - const uri = `/v1/binaries/${binaryId}`; - const req = request('get', uri); - req.use(this.prefix); - this.headers(req, auth); - return req; + let req = this.request({ + uri: `/v1/binaries/${binaryId}`, + method: 'get', + raw: true, + auth + }); + + return this._provideFileData(req); } /** @@ -1131,17 +1133,8 @@ class Particle { * @returns {Promise} Resolves to a buffer with the file data */ downloadFile({ url }){ - let req = request.get(url); - // Different API in Node and browser - if (!request.getXHR){ - req = req.buffer(true).parse(binaryParser); - } else if (req.responseType){ - req = req.responseType('arraybuffer').then(res => { - res.body = res.xhr.response; - return res; - }); - } - return req.then(res => res.body); + let req = this.request({ uri: url, method: 'get', raw: true }); + return this._provideFileData(req); } /** @@ -1299,11 +1292,26 @@ class Particle { * @returns {Request} A promise */ downloadProductFirmware({ version, product, auth }){ - const uri = `/v1/products/${product}/firmware/${version}/binary`; - const req = request('get', uri); - req.use(this.prefix); - this.headers(req, auth); - return req; + let req = this.request({ + uri: `/v1/products/${product}/firmware/${version}/binary`, + method: 'get', + raw: true, + auth + }); + + return this._provideFileData(req); + } + + _provideFileData(req){ + if (this.agent.isForBrowser()){ + req = req.responseType('arraybuffer').then(res => { + res.body = res.xhr.response; + return res; + }); + } else { + req = req.buffer(true).parse(binaryParser); + } + return req.then(res => res.body); } /** diff --git a/test/Particle.spec.js b/test/Particle.spec.js index aea4618..ef35f98 100644 --- a/test/Particle.spec.js +++ b/test/Particle.spec.js @@ -29,6 +29,7 @@ const props = { files: { 'app.ino': new Buffer('void(){}\nsetup(){}\n') }, + binaryId: '123456', targetVersion: '0.4.7', requestType: 'GET', headers: { @@ -712,6 +713,21 @@ describe('ParticleAPI', () => { }); }); }); + describe('.downloadFirmwareBinary', () => { + it('generates request', () => { + sinon.stub(api, '_provideFileData').callsFake(x => Promise.resolve(x)); + const req = api.downloadFirmwareBinary(propsWithProduct); + api._provideFileData.callCount.should.equal(1); + return req.then((results) => { + results.should.match({ + uri: `/v1/binaries/${props.binaryId}`, + method: 'get', + auth: props.auth, + raw: true + }); + }); + }); + }); describe('.sendPublicKey', () => { it('generates request', () => { return api.sendPublicKey(props).then(Common.expectDeviceUrlAndToken); @@ -1574,7 +1590,17 @@ describe('ParticleAPI', () => { }); }); }); - + describe('.downloadFile', () => { + it('generates request', () => { + sinon.stub(api, '_provideFileData').callsFake(x => Promise.resolve(x)); + const uri = 'http://example.com/path/to/file.png'; + const req = api.downloadFile({ url: uri }); + api._provideFileData.callCount.should.equal(1); + return req.then((results) => { + results.should.match({ uri, method: 'get', raw: true }); + }); + }); + }); describe('.listOAuthClients', () => { describe('user scope', () => { it('generates request', () => { @@ -1751,6 +1777,22 @@ describe('ParticleAPI', () => { }); }); + describe('.downloadProductFirmware', () => { + it('generates request', () => { + sinon.stub(api, '_provideFileData').callsFake(x => Promise.resolve(x)); + const req = api.downloadProductFirmware(propsWithProduct); + api._provideFileData.callCount.should.equal(1); + return req.then((results) => { + results.should.match({ + uri: `/v1/products/${product}/firmware/${props.version}/binary`, + method: 'get', + auth: props.auth, + raw: true + }); + }); + }); + }); + describe('.getProductFirmware', () => { it('generates request', () => { return api.getProductFirmware(propsWithProduct).then((results) => {