1 | dns = require 'http-dns'
|
2 | qs = require 'qs'
|
3 | superagent = require 'superagent'
|
4 | url = require 'url'
|
5 |
|
6 | _ = {
|
7 | defaults: require 'lodash/defaults'
|
8 | dropRight: require 'lodash/dropRight'
|
9 | each: require 'lodash/each'
|
10 | isEmpty: require 'lodash/isEmpty'
|
11 | join: require 'lodash/join'
|
12 | minBy: require 'lodash/minBy'
|
13 | pick: require 'lodash/pick'
|
14 | split: require 'lodash/split'
|
15 | takeRight: require 'lodash/takeRight'
|
16 | }
|
17 |
|
18 | discardReturn = require './discard-return.coffee'
|
19 |
|
20 | class MeshbluRequest
|
21 | constructor: (options={}) ->
|
22 | {@protocol, @hostname, @port} = options
|
23 | {@service, @domain, @secure, @resolveSrv} = options
|
24 | {@dnsHttpServer} = options
|
25 |
|
26 | delete: (pathname, options, callback) =>
|
27 | requestOptions = _.pick(options, 'uuid', 'token', 'bearerToken', 'headers')
|
28 | requestOptions.pathname = pathname
|
29 | query = qs.stringify options.query
|
30 |
|
31 | @_resolveBaseUrl (error, baseUri) =>
|
32 | return callback error if error?
|
33 | @_request('delete', baseUri, requestOptions).query(query).end @_handleResponse(callback)
|
34 |
|
35 | get: (pathname, options, callback) =>
|
36 | requestOptions = _.pick(options, 'uuid', 'token', 'bearerToken', 'headers')
|
37 | requestOptions.pathname = pathname
|
38 | query = qs.stringify options.query
|
39 |
|
40 | @_resolveBaseUrl (error, baseUri) =>
|
41 | return callback error if error?
|
42 | @_request('get', baseUri, requestOptions).query(query).end @_handleResponse(callback)
|
43 |
|
44 | patch: (pathname, options, callback) =>
|
45 | requestOptions = _.pick(options, 'uuid', 'token', 'bearerToken', 'headers')
|
46 | requestOptions.pathname = pathname
|
47 | body = options.body
|
48 |
|
49 | @_resolveBaseUrl (error, baseUri) =>
|
50 | return callback error if error?
|
51 | @_request('patch', baseUri, requestOptions).send(body).end @_handleResponse(callback)
|
52 |
|
53 | post: (pathname, options, callback) =>
|
54 | requestOptions = _.pick(options, 'uuid', 'token', 'bearerToken', 'headers')
|
55 | requestOptions.pathname = pathname
|
56 | body = options.body
|
57 |
|
58 | @_resolveBaseUrl (error, baseUri) =>
|
59 | return callback error if error?
|
60 | @_request('post', baseUri, requestOptions).send(body).end @_handleResponse(callback)
|
61 |
|
62 | put: (pathname, options, callback) =>
|
63 | requestOptions = _.pick(options, 'uuid', 'token', 'bearerToken', 'headers')
|
64 | requestOptions.pathname = pathname
|
65 | body = options.body
|
66 |
|
67 | @_resolveBaseUrl (error, baseUri) =>
|
68 | return callback error if error?
|
69 | @_request('put', baseUri, requestOptions).send(body).end @_handleResponse(callback)
|
70 |
|
71 | _getDomain: =>
|
72 | parts = _.split @hostname, '.'
|
73 | domainParts = _.takeRight parts, 2
|
74 | return _.join domainParts, '.'
|
75 |
|
76 | _getSrvAddress: =>
|
77 | return "_#{@service}._#{@_getSrvProtocol()}.#{@domain}"
|
78 |
|
79 | _getSrvProtocol: =>
|
80 | return 'https' if @secure
|
81 | return 'http'
|
82 |
|
83 | _getSubdomain: =>
|
84 | parts = _.split @hostname, '.'
|
85 | subdomainParts = _.dropRight parts, 2
|
86 | return _.join subdomainParts, '.'
|
87 |
|
88 | _handleResponse: (callback) => (error, response) =>
|
89 | return callback error if error?
|
90 | return callback null if response.notFound
|
91 | return callback new Error 'Invalid Response Code' unless response.ok
|
92 | return callback null, response.body
|
93 |
|
94 | _request: (method, baseUri, {pathname, uuid, token, bearerToken, headers}) =>
|
95 | theRequest = superagent[method](@_url baseUri, pathname)
|
96 | theRequest.auth uuid, token if uuid? && token?
|
97 | theRequest.set('Authorization', "Bearer #{bearerToken}") if bearerToken?
|
98 | theRequest.accept('application/json')
|
99 | theRequest.set('Content-Type', 'application/json')
|
100 | _.each headers, (value, key) =>
|
101 | theRequest.set key, value
|
102 | return theRequest
|
103 |
|
104 | _resolveBaseUrl: (cb) =>
|
105 | callback = discardReturn cb
|
106 |
|
107 | return callback null, url.format {@protocol, @hostname, @port} unless @resolveSrv
|
108 |
|
109 | dns.resolveSrv @_getSrvAddress(), (error, addresses) =>
|
110 | return callback error if error?
|
111 | return callback new Error('SRV record found, but contained no valid addresses') if _.isEmpty addresses
|
112 | return callback null, @_resolveUrlFromAddresses(addresses)
|
113 |
|
114 | _resolveUrlFromAddresses: (addresses) =>
|
115 | address = _.minBy addresses, 'priority'
|
116 | return url.format {
|
117 | protocol: @_getSrvProtocol()
|
118 | hostname: address.name
|
119 | port: address.port
|
120 | }
|
121 |
|
122 | _url: (baseUri, pathname) =>
|
123 | {protocol, hostname, port} = url.parse baseUri
|
124 | return url.format({ hostname, protocol, port, pathname })
|
125 |
|
126 | module.exports = MeshbluRequest
|