1 | _ = require 'lodash'
|
2 | async = require 'async'
|
3 | MeshbluHttp = require 'browser-meshblu-http'
|
4 | MeshbluHose = require 'meshblu-firehose-socket.io/src/firehose-socket-io.coffee'
|
5 | EventEmitter = require 'eventemitter2'
|
6 |
|
7 | class Inquisitor extends EventEmitter
|
8 | constructor: ({meshbluConfig, @firehoseConfig, uuid}) ->
|
9 | @meshblu = new MeshbluHttp meshbluConfig
|
10 | @inquisitorUuid = uuid
|
11 |
|
12 | setup: (callback) =>
|
13 | @meshblu.device @inquisitorUuid, (error, device) =>
|
14 | return callback error if error?
|
15 |
|
16 | devices = device.devices
|
17 |
|
18 | @_createSubscription @inquisitorUuid, (error) =>
|
19 | return callback error if error?
|
20 |
|
21 | @getStatusDevices devices, (error, statusDevices) =>
|
22 | return callback error if error?
|
23 | allDevices = _.union devices, statusDevices
|
24 |
|
25 | @createSubscriptions allDevices, (error) =>
|
26 | return callback error if error?
|
27 | @updatePermissions allDevices, callback
|
28 |
|
29 | connect: (callback) =>
|
30 | @getMonitoredDevices (error, @monitoredDevices) =>
|
31 | return callback error if error?
|
32 | @meshblu.generateAndStoreToken @inquisitorUuid, {}, (error, response) =>
|
33 | return callback error if error?
|
34 | @firehose = new MeshbluHose({
|
35 | meshbluConfig: {
|
36 | hostname: @firehoseConfig.hostname
|
37 | port: @firehoseConfig.port,
|
38 | protocol: @firehoseConfig.protocol
|
39 | uuid: @inquisitorUuid,
|
40 | token: response.token
|
41 | }
|
42 | })
|
43 |
|
44 | @firehose.on 'message', @_onMessage
|
45 |
|
46 |
|
47 | @firehose.connect {uuid: @inquisitorUuid}, callback
|
48 |
|
49 | _onMessage: ({metadata, data}) =>
|
50 | @emit 'message', {metadata, data}
|
51 | return unless _.last(metadata.route).type == 'configure.received'
|
52 |
|
53 | statusDevice = _.last(_.initial(metadata.route)).from
|
54 | {device} = _.find @monitoredDevices, {statusDevice}
|
55 | device = data if device.uuid == statusDevice
|
56 |
|
57 | emitMessage =
|
58 | uuid: device.uuid
|
59 | statusDevice: statusDevice
|
60 | errors: data.errors
|
61 | device: device
|
62 |
|
63 | @emit 'status-update', emitMessage
|
64 |
|
65 |
|
66 | stop: (callback) =>
|
67 | return callback() unless @firehose?
|
68 | @firehose.close callback
|
69 |
|
70 | getStatusDevices: (devices, callback) =>
|
71 | @meshblu.search {query: {uuid: $in: devices }, projection: {statusDevice: true }}, (error, newDevices) =>
|
72 | return callback error if error?
|
73 | statusDevices = _.compact _.map newDevices, 'statusDevice'
|
74 | callback null, statusDevices
|
75 |
|
76 | getMonitoredDevices: (callback) =>
|
77 | @meshblu.listSubscriptions {subscriberUuid: @inquisitorUuid}, (error, subscriptions) =>
|
78 | return callback error if error?
|
79 | subscribedDevices = _.without _.map(subscriptions, 'emitterUuid'), @inquisitorUuid
|
80 | @meshblu.search {query: {uuid: $in: subscribedDevices}}, (error, devices) =>
|
81 | return callback error if error?
|
82 | callback null, @mapStatusDevices devices
|
83 |
|
84 | mapStatusDevices: (devices) =>
|
85 | _.compact _.map devices, (device) =>
|
86 | return if _.some devices, statusDevice: device.uuid
|
87 | return {uuid: device.uuid, device, statusDevice: device.uuid, errors: device.errors} unless device.statusDevice?
|
88 | statusDevice = _.find devices, uuid: device.statusDevice
|
89 | return {uuid: device.uuid, device, statusDevice: device.statusDevice, errors: statusDevice?.errors || []}
|
90 |
|
91 |
|
92 | createSubscriptions: (devices, callback) =>
|
93 | async.each devices, @_createSubscription, callback
|
94 |
|
95 | _createSubscription: (device, callback) =>
|
96 | subscriptions = [
|
97 | {subscriberUuid: @inquisitorUuid, emitterUuid: device, type: 'configure.received'}
|
98 | {subscriberUuid: @inquisitorUuid, emitterUuid: device, type: 'message.received'}
|
99 | {subscriberUuid: @inquisitorUuid, emitterUuid: device, type: 'message.sent'}
|
100 | {subscriberUuid: @inquisitorUuid, emitterUuid: device, type: 'broadcast.sent'}
|
101 | ]
|
102 | async.eachSeries subscriptions, @meshblu.createSubscription, callback
|
103 |
|
104 | updatePermissions: (devices, callback) =>
|
105 | @meshblu.search {query: {uuid: {$in: devices}, 'meshblu.version': '2.0.0'}, projection: {uuid: true}}, (error, v2Devices) =>
|
106 | return callback error if error?
|
107 | v2Devices = _.map v2Devices, 'uuid'
|
108 | v1Devices = _.difference devices, v2Devices
|
109 | @updateV1Devices v1Devices, (error) =>
|
110 | return callback error if error?
|
111 | @updateV2Devices v2Devices, callback
|
112 |
|
113 | updateV1Devices: (devices, callback) =>
|
114 | async.each devices, @_updateV1Device, callback
|
115 |
|
116 | _updateV1Device: (device, callback) =>
|
117 | update =
|
118 | $addToSet:
|
119 | configureWhitelist: @inquisitorUuid
|
120 | discoverWhitelist: @inquisitorUuid
|
121 | @meshblu.updateDangerously device, update, callback
|
122 |
|
123 | updateV2Devices: (devices, callback) =>
|
124 | async.each devices, @_updateV2Device, callback
|
125 |
|
126 | _updateV2Device: (device, callback) =>
|
127 | update =
|
128 | $addToSet:
|
129 | 'meshblu.whitelists.configure.received': uuid: @inquisitorUuid
|
130 | 'meshblu.whitelists.discover.view': uuid: @inquisitorUuid
|
131 |
|
132 | @meshblu.updateDangerously device, update, callback
|
133 |
|
134 | clearErrors: (uuid, callback) =>
|
135 | update =
|
136 | $unset:
|
137 | errors: true
|
138 | @meshblu.updateDangerously uuid, update, callback
|
139 |
|
140 | getMonitoredDeviceSubscriptions: (callback) =>
|
141 | @meshblu.listSubscriptions {subscriberUuid: @inquisitorUuid}, (error, subscriptions) =>
|
142 | return callback error if error?
|
143 | subscriptionQueries =
|
144 | _(subscriptions)
|
145 | .uniqBy('emitterUuid')
|
146 | .reject emitterUuid: @inquisitorUuid
|
147 | .map ({emitterUuid}) => {subscriberUuid: emitterUuid}
|
148 | .compact()
|
149 | .value()
|
150 |
|
151 | async.map subscriptionQueries, @meshblu.listSubscriptions, (error, subscriptions) =>
|
152 | return callback error, _.flatten(subscriptions)
|
153 |
|
154 | module.exports = Inquisitor
|