Skip to content
This repository was archived by the owner on Mar 10, 2020. It is now read-only.

[discuss] Switch to superagent instead of raw http.request #92

Merged
merged 1 commit into from
Nov 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"parser": "babel-eslint",
"extends": "standard"
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"merge-stream": "^1.0.0",
"multiaddr": "^1.0.0",
"multipart-stream": "^2.0.0",
"request": "^2.65.0",
"vinyl": "^0.5.1",
"vinyl-fs-browser": "^2.1.1-1",
"vinyl-multipart-stream": "^1.2.6"
Expand All @@ -25,7 +26,7 @@
"url": "https://github.com/ipfs/js-ipfs-api"
},
"devDependencies": {
"brfs": "^1.4.1",
"babel-eslint": "^4.1.3",
"browserify": "^11.0.0",
"concurrently": "^0.1.1",
"eslint-config-standard": "^4.4.0",
Expand Down
3 changes: 1 addition & 2 deletions src/get-files-stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ exports = module.exports = getFilesStream

function getFilesStream (files, opts) {
if (!files) return null
if (!Array.isArray(files)) files = [files]

// merge all inputs into one stream
var adder = new Merge()
Expand All @@ -31,7 +30,7 @@ function getFilesStream (files, opts) {
adder.add(vinylfs.src(file, srcOpts))

// if recursive, glob the contents
if (opts.r || opts.recursive) {
if (opts.recursive) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why no more r?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm merging the r option with the recursive option in the configuration setup, so later down the line it's only one option to check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it, nice :)

adder.add(vinylfs.src(file + '/**/*', srcOpts))
}
} else {
Expand Down
199 changes: 107 additions & 92 deletions src/request-api.js
Original file line number Diff line number Diff line change
@@ -1,108 +1,123 @@
var http = require('http')
var qs = require('querystring')
var getFilesStream = require('./get-files-stream')
'use strict'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've read that this is required for 'let' to work properly, is it the reason why you added?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes


exports = module.exports = function getRequestAPI (config) {
return requestAPI
const request = require('request')
const getFilesStream = require('./get-files-stream')

function requestAPI (path, args, opts, files, buffer, cb) {
var query, stream, contentType
contentType = 'application/json'
const isNode = !global.window

if (Array.isArray(path)) path = path.join('/')
// -- Internal

opts = opts || {}
function onEnd (buffer, result, cb) {
return (err, res, body) => {
if (err) {
return cb(err)
}

if (args && !Array.isArray(args)) args = [args]
if (args) opts.arg = args
if (res.statusCode >= 400 || !res.statusCode) {
return cb(new Error(`Server responded with ${res.statusCode}: ${body}`))
}

if (files) {
stream = getFilesStream(files, opts)
if (!stream.boundary) {
throw new Error('no boundary in multipart stream')
}
contentType = 'multipart/form-data; boundary=' + stream.boundary
if ((result.stream && !buffer) ||
(result.chunkedObjects && buffer)) {
return cb(null, body)
}

if (typeof buffer === 'function') {
cb = buffer
buffer = false
if (result.chunkedObjects) return cb(null, result.objects)

try {
const parsedBody = JSON.parse(body)
cb(null, parsedBody)
} catch (e) {
cb(null, body)
}
}
}

// this option is only used internally, not passed to daemon
delete opts.followSymlinks

opts['stream-channels'] = true
query = qs.stringify(opts)

var reqo = {
method: files ? 'POST' : 'GET',
host: config.host,
port: config.port,
path: config['api-path'] + path + '?' + query,
headers: {
'User-Agent': config['user-agent'],
'Content-Type': contentType
},
withCredentials: false
function onData (result) {
return chunk => {
if (!result.chunkedObjects) return

try {
const obj = JSON.parse(chunk.toString())
result.objects.push(obj)
} catch (e) {
result.chunkedObjects = false
}
}
}

function onResponse (result) {
return res => {
result.stream = !!res.headers['x-stream-output']
result.chunkedObjects = !!res.headers['x-chunked-output']
}
}

function makeRequest (opts, buffer, cb) {
// this option is only used internally, not passed to daemon
delete opts.qs.followSymlinks

const result = {
stream: false,
chunkedObjects: false,
objects: []
}

return request(opts, onEnd(buffer, result, cb))
.on('data', onData(result))
.on('response', onResponse(result))
}

function requestAPI (config, path, args, qs, files, buffer, cb) {
qs = qs || {}
if (Array.isArray(path)) path = path.join('/')
if (args && !Array.isArray(args)) args = [args]
if (args) qs.arg = args
if (files && !Array.isArray(files)) files = [files]

if (typeof buffer === 'function') {
cb = buffer
buffer = false
}

if (qs.r) qs.recursive = qs.r

if (!isNode && qs.recursive && path === 'add') {
return cb(new Error('Recursive uploads are not supported in the browser'))
}

qs['stream-channels'] = true

var req = http.request(reqo, function (res) {
var data = ''
var objects = []
var stream = !!res.headers && !!res.headers['x-stream-output']
var chunkedObjects = !!res.headers && !!res.headers['x-chunked-output']

if (stream && !buffer) return cb(null, res)
if (chunkedObjects && buffer) return cb(null, res)

res.on('data', function (chunk) {
if (!chunkedObjects) {
data += chunk
return data
}

try {
var obj = JSON.parse(chunk.toString())
objects.push(obj)
} catch (e) {
chunkedObjects = false
data += chunk
}
})
res.on('end', function () {
var parsed

if (!chunkedObjects) {
try {
parsed = JSON.parse(data)
data = parsed
} catch (e) {}
} else {
data = objects
}

if (res.statusCode >= 400 || !res.statusCode) {
if (!data) data = new Error()
return cb(data, null)
}
return cb(null, data)
})
res.on('error', function (err) {
return cb(err, null)
})
})

req.on('error', function (err) {
return cb(err, null)
})

if (stream) {
stream.pipe(req)
} else {
req.end()
const opts = {
method: files ? 'POST' : 'GET',
uri: `http://${config.host}:${config.port}${config['api-path']}${path}`,
qs: qs,
useQuerystring: true,
headers: {},
withCredentials: false,
gzip: true
}

if (isNode) {
// Browsers do not allow you to modify the user agent
opts.headers['User-Agent'] = config['user-agent']
}

if (files) {
const stream = getFilesStream(files, qs)
if (!stream.boundary) {
return cb(new Error('No boundary in multipart stream'))
}

return req
opts.headers['Content-Type'] = `multipart/form-data; boundary=${stream.boundary}`
stream.pipe(makeRequest(opts, buffer, cb))
} else {
makeRequest(opts, buffer, cb)
}
}

// -- Interface

exports = module.exports = function getRequestAPI (config) {
return requestAPI.bind(null, config)
}
17 changes: 9 additions & 8 deletions test/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,18 +130,19 @@ describe('IPFS Node.js API wrapper tests', function () {
})

it('add a nested dir', function (done) {
if (!isNode) {
return done()
}
this.timeout(10000)

apiClients['a'].add(__dirname + '/test-folder', { recursive: true }, function (err, res) {
if (err) {
throw err
if (isNode) {
if (err) throw err

var added = res[res.length - 1]
assert.equal(added.Hash, 'QmZdsefMGMeG6bL719gX44XSVQrL6psEgRZdw1SGadFaK2')
done()
} else {
assert.equal(err.message, 'Recursive uploads are not supported in the browser')
done()
}
var added = res[res.length - 1]
assert.equal(added.Hash, 'QmZdsefMGMeG6bL719gX44XSVQrL6psEgRZdw1SGadFaK2')
done()
})
})
})
Expand Down