2014-11-18 13:59:19 +00:00
|
|
|
_ = require('lodash')
|
2014-10-31 15:59:23 +00:00
|
|
|
request = require('request')
|
2014-12-01 17:23:47 +00:00
|
|
|
progress = require('request-progress')
|
2014-11-14 15:05:30 +00:00
|
|
|
async = require('async')
|
2014-11-26 16:07:10 +00:00
|
|
|
connection = require('../../connection/connection')
|
2014-12-03 16:03:54 +00:00
|
|
|
settings = require('../settings')
|
2014-12-22 18:43:38 +00:00
|
|
|
auth = require('../auth/auth')
|
2014-10-31 15:59:23 +00:00
|
|
|
|
2014-12-08 12:48:39 +00:00
|
|
|
# @nodoc
|
|
|
|
urlResolve = require('url').resolve
|
|
|
|
|
|
|
|
# Send an HTTP request to resin.io
|
|
|
|
#
|
|
|
|
# @param {Object} options request options
|
|
|
|
# @option options {String} url relative url
|
|
|
|
# @option options {String} json request body
|
|
|
|
# @option options {String} method HTTP method
|
|
|
|
# @option options {Object} headers custom HTTP headers
|
|
|
|
# @option options {Function} pipe define this function if you want to stream the response
|
|
|
|
#
|
|
|
|
# @param {Function} callback callback(error, response, body)
|
|
|
|
# @param {Function} onProgress on progress callback(state) (optional)
|
|
|
|
#
|
|
|
|
# @note If the user is logged in, the token gets automatically added to Authorization header
|
|
|
|
# @note If the response is JSON, it will attempt to parse it
|
|
|
|
#
|
|
|
|
# @throw {Error} Will throw if you don't have internet connection
|
|
|
|
#
|
|
|
|
# @example GET request
|
|
|
|
# resin.server.request {
|
|
|
|
# method: 'GET'
|
|
|
|
# url: '/foobar'
|
|
|
|
# }, (error, response, body) ->
|
|
|
|
# throw error if error?
|
|
|
|
# console.log(body)
|
|
|
|
#
|
|
|
|
# @example POST request with body
|
|
|
|
# resin.server.request {
|
|
|
|
# method: 'POST'
|
|
|
|
# url: '/foobar'
|
|
|
|
# json:
|
|
|
|
# name: 'My FooBar'
|
|
|
|
# }, (error, response, body) ->
|
|
|
|
# throw error if error?
|
|
|
|
# assert(response.statusCode is 201)
|
|
|
|
#
|
|
|
|
# @example Stream download
|
|
|
|
# resin.server.request {
|
|
|
|
# method: 'GET'
|
|
|
|
# url: '/download'
|
|
|
|
# pipe: fs.createWriteStream('/tmp/download')
|
|
|
|
# }, (error) ->
|
|
|
|
# throw error if error?
|
|
|
|
# , (state) ->
|
|
|
|
# console.log("Received: #{state.received}")
|
|
|
|
# console.log("Total: #{state.total}")
|
|
|
|
# console.log("Is Complete? #{state.complete}")
|
|
|
|
#
|
2014-12-02 14:57:47 +00:00
|
|
|
exports.request = (options = {}, outerCallback, onProgress) ->
|
2014-12-01 17:23:47 +00:00
|
|
|
|
|
|
|
onProgress ?= _.noop
|
2014-11-18 13:59:19 +00:00
|
|
|
|
|
|
|
if not options.url?
|
|
|
|
throw new Error('Missing URL')
|
2014-10-31 15:59:23 +00:00
|
|
|
|
2014-11-14 15:05:30 +00:00
|
|
|
async.waterfall [
|
2014-10-31 15:59:23 +00:00
|
|
|
|
2014-11-14 15:05:30 +00:00
|
|
|
(callback) ->
|
2014-11-24 18:55:05 +00:00
|
|
|
connection.isOnline(callback)
|
|
|
|
|
|
|
|
(isOnline, callback) ->
|
|
|
|
if not isOnline
|
|
|
|
return callback(new Error('You need internet connection to perform this task'))
|
|
|
|
|
2014-12-22 18:43:38 +00:00
|
|
|
auth.getToken(callback)
|
2014-10-31 17:25:02 +00:00
|
|
|
|
2014-11-14 15:05:30 +00:00
|
|
|
(savedToken, callback) ->
|
2014-12-05 14:53:59 +00:00
|
|
|
options.url = urlResolve(settings.get('remoteUrl'), options.url)
|
2014-11-18 13:59:19 +00:00
|
|
|
|
|
|
|
if options.method?
|
|
|
|
options.method = options.method.toUpperCase()
|
|
|
|
|
|
|
|
_.defaults options,
|
|
|
|
method: 'GET'
|
2014-11-18 14:05:38 +00:00
|
|
|
gzip: true
|
2014-10-31 15:59:23 +00:00
|
|
|
|
2014-11-14 15:05:30 +00:00
|
|
|
if savedToken?
|
2014-11-18 14:04:26 +00:00
|
|
|
options.headers ?= {}
|
|
|
|
_.extend options.headers,
|
2014-11-14 15:05:30 +00:00
|
|
|
'Authorization': "Bearer #{savedToken}"
|
2014-10-31 15:59:23 +00:00
|
|
|
|
2014-12-02 14:57:47 +00:00
|
|
|
if options.pipe?
|
|
|
|
progress(request(options))
|
|
|
|
.on('progress', onProgress)
|
|
|
|
.on('error', outerCallback)
|
|
|
|
.on('end', onProgress)
|
|
|
|
.pipe(options.pipe)
|
|
|
|
.on('error', outerCallback)
|
|
|
|
.on('close', outerCallback)
|
|
|
|
else
|
|
|
|
return request(options, callback)
|
2014-10-31 15:59:23 +00:00
|
|
|
|
2014-11-14 15:05:30 +00:00
|
|
|
(response, body, callback) ->
|
|
|
|
try
|
|
|
|
response.body = JSON.parse(response.body)
|
2014-10-31 15:59:23 +00:00
|
|
|
|
2014-11-14 15:05:30 +00:00
|
|
|
if response?.statusCode >= 400
|
|
|
|
error = new Error(response.body)
|
2014-10-31 15:59:23 +00:00
|
|
|
|
2014-11-14 15:53:46 +00:00
|
|
|
return callback(error, response, response.body)
|
2014-10-31 15:59:23 +00:00
|
|
|
|
2014-12-02 14:57:47 +00:00
|
|
|
], outerCallback
|
2014-11-14 15:05:30 +00:00
|
|
|
|
2014-12-08 12:48:39 +00:00
|
|
|
# Generate shorthand functions for every method
|
|
|
|
#
|
|
|
|
# @private
|
|
|
|
#
|
|
|
|
# @todo Find a way to document all of the methods directly
|
|
|
|
#
|
2014-11-18 14:33:24 +00:00
|
|
|
createFacadeFunction = (method) ->
|
|
|
|
lowerCaseMethod = method.toLowerCase()
|
2014-12-01 17:23:47 +00:00
|
|
|
exports[lowerCaseMethod] = (url, body, callback, onProgress) ->
|
2014-11-18 14:33:24 +00:00
|
|
|
options = {
|
|
|
|
method
|
|
|
|
url
|
|
|
|
}
|
|
|
|
|
|
|
|
if _.isFunction(body)
|
2014-12-01 17:23:47 +00:00
|
|
|
onProgress = callback
|
2014-11-18 14:33:24 +00:00
|
|
|
callback = body
|
|
|
|
else
|
|
|
|
options.json = body
|
|
|
|
|
2014-12-01 17:23:47 +00:00
|
|
|
return exports.request(options, callback, onProgress)
|
2014-11-18 14:33:24 +00:00
|
|
|
|
|
|
|
for method in [
|
|
|
|
'GET'
|
|
|
|
'HEAD'
|
|
|
|
'POST'
|
|
|
|
'PATCH'
|
|
|
|
'PUT'
|
|
|
|
'DELETE'
|
|
|
|
]
|
|
|
|
createFacadeFunction(method)
|