@itentialopensource/adapter-utils 4.48.16 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +2 -0
- package/lib/brokerHandler.js +730 -0
- package/lib/cacheHandler.js +968 -0
- package/lib/connectorRest.js +28 -13
- package/lib/dbUtil.js +0 -3
- package/lib/genericHandler.js +280 -0
- package/lib/propertyUtil.js +134 -3
- package/lib/requestHandler.js +780 -209
- package/lib/translatorUtil.js +5 -4
- package/package.json +26 -26
- package/refs?service=git-upload-pack +0 -0
- package/schemas/propertiesSchema.json +576 -1
|
@@ -0,0 +1,730 @@
|
|
|
1
|
+
/* @copyright Itential, LLC 2023 */
|
|
2
|
+
|
|
3
|
+
// Set globals
|
|
4
|
+
/* global log */
|
|
5
|
+
/* eslint global-require:warn */
|
|
6
|
+
/* eslint import/no-dynamic-require:warn */
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
/* NodeJS internal utilities */
|
|
12
|
+
|
|
13
|
+
let adapterDir = '';
|
|
14
|
+
let id = '';
|
|
15
|
+
|
|
16
|
+
/*
|
|
17
|
+
* INTERNAL FUNCTION: update device broker properties from service instance config and adapter sample properties
|
|
18
|
+
*/
|
|
19
|
+
function getDeviceBrokerArray(allProps) {
|
|
20
|
+
const origin = `${id}-brokerHandler-getDeviceBrokerArray`;
|
|
21
|
+
log.trace(origin);
|
|
22
|
+
const brokerCallsArr = ['getDevice', 'getDevicesFiltered', 'isAlive', 'getConfig', 'getCount'];
|
|
23
|
+
const deviceBrokerProps = allProps.devicebroker;
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const sampleFile = path.join(adapterDir, '/sampleProperties.json');
|
|
27
|
+
let sampleProps = null;
|
|
28
|
+
if (fs.existsSync(sampleFile)) {
|
|
29
|
+
sampleProps = require(path.resolve(adapterDir, 'sampleProperties.json')).properties;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// go through all the device broker calls to get the call information
|
|
33
|
+
for (let i = 0; i < brokerCallsArr.length; i += 1) {
|
|
34
|
+
// If in service config that is primary - e.g do nothing
|
|
35
|
+
if (!allProps.devicebroker || !allProps.devicebroker[brokerCallsArr[i]] || allProps.devicebroker[brokerCallsArr[i]].length === 0 || !allProps.devicebroker[brokerCallsArr[i]][0].path) {
|
|
36
|
+
// if not in service config check sample props
|
|
37
|
+
if (!sampleProps.devicebroker || !sampleProps.devicebroker[brokerCallsArr[i]] || sampleProps.devicebroker[brokerCallsArr[i]].length === 0 || !sampleProps.devicebroker[brokerCallsArr[i]][0].path) {
|
|
38
|
+
// not in sample properties, nothing we can do
|
|
39
|
+
log.info(`No device broker props found for ${brokerCallsArr[i]}`);
|
|
40
|
+
deviceBrokerProps[brokerCallsArr[i]] = [];
|
|
41
|
+
} else {
|
|
42
|
+
// use the sample properties information
|
|
43
|
+
log.info(`Updating device broker props for ${brokerCallsArr[i]} from sample props`);
|
|
44
|
+
deviceBrokerProps[brokerCallsArr[i]] = sampleProps.devicebroker[brokerCallsArr[i]];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
log.debug('Device broker array', JSON.stringify(deviceBrokerProps, null, 3));
|
|
50
|
+
return deviceBrokerProps;
|
|
51
|
+
} catch (ex) {
|
|
52
|
+
return {};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
class BrokerHandler {
|
|
57
|
+
/**
|
|
58
|
+
* Adapter Broker Handler
|
|
59
|
+
* @constructor
|
|
60
|
+
*/
|
|
61
|
+
constructor(prongId, properties, directory, reqH) {
|
|
62
|
+
this.myid = prongId;
|
|
63
|
+
id = prongId;
|
|
64
|
+
this.allProps = properties;
|
|
65
|
+
adapterDir = directory;
|
|
66
|
+
this.requestHandlerInst = reqH;
|
|
67
|
+
|
|
68
|
+
// set up the properties I care about
|
|
69
|
+
this.refreshProperties(properties);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* refreshProperties is used to set up all of the properties for the broker handler.
|
|
74
|
+
* It allows properties to be changed later by simply calling refreshProperties rather
|
|
75
|
+
* than having to restart the broker handler.
|
|
76
|
+
*
|
|
77
|
+
* @function refreshProperties
|
|
78
|
+
* @param {Object} properties - an object containing all of the properties
|
|
79
|
+
*/
|
|
80
|
+
refreshProperties(properties) {
|
|
81
|
+
const origin = `${this.myid}-brokerHandler-refreshProperties`;
|
|
82
|
+
log.trace(origin);
|
|
83
|
+
|
|
84
|
+
if (!properties) {
|
|
85
|
+
log.error(`${origin}: Broker Handler received no properties!`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// update deviceBrokerProperties
|
|
90
|
+
this.allProps.devicebroker = getDeviceBrokerArray(properties);
|
|
91
|
+
|
|
92
|
+
// this.
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @summary Determines if this adapter supports any in a list of entities
|
|
97
|
+
*
|
|
98
|
+
* @function hasEntities
|
|
99
|
+
* @param {String} entityType - the entity type to check for
|
|
100
|
+
* @param {Array} entityList - the list of entities we are looking for
|
|
101
|
+
*
|
|
102
|
+
* @param {Callback} callback - A map where the entity is the key and the
|
|
103
|
+
* value is true or false
|
|
104
|
+
*/
|
|
105
|
+
hasEntities(entityType, entityList, callback) {
|
|
106
|
+
const origin = `${this.myid}-brokerHandler-hasEntities`;
|
|
107
|
+
log.trace(origin);
|
|
108
|
+
|
|
109
|
+
switch (entityType) {
|
|
110
|
+
case 'Device':
|
|
111
|
+
return this.hasDevices(entityList, callback);
|
|
112
|
+
default:
|
|
113
|
+
return callback(null, `${this.myid} does not support entity ${entityType}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @summary Helper method for hasEntities for the specific device case
|
|
119
|
+
*
|
|
120
|
+
* @param {Array} deviceList - array of unique device identifiers, name
|
|
121
|
+
* @param {Callback} callback - A map where the device is the key and the
|
|
122
|
+
* value is true or false
|
|
123
|
+
*/
|
|
124
|
+
hasDevices(deviceList, callback) {
|
|
125
|
+
const origin = `${this.myid}-brokerHandler-hasDevices`;
|
|
126
|
+
log.trace(origin);
|
|
127
|
+
|
|
128
|
+
let findings = {}; // map
|
|
129
|
+
|
|
130
|
+
if (this.allProps.cache.enabled) { // a bit redundant but just in case errors in cacheHandler
|
|
131
|
+
let entityTypeCached = false;
|
|
132
|
+
this.requestHandlerInst.checkEntityTypeCached('Device', (res, error) => {
|
|
133
|
+
if (error) {
|
|
134
|
+
log.error(`${origin}: cache check failed with error ${error}`);
|
|
135
|
+
// continue as if cache disabled, "try again"
|
|
136
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, origin, error, null, null, null);
|
|
137
|
+
return callback(null, errorObj);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (res) {
|
|
141
|
+
entityTypeCached = true;
|
|
142
|
+
// EntityType is cached. Retrieve devices from cache
|
|
143
|
+
return this.requestHandlerInst.checkEntityCached('Device', deviceList, (results, err) => {
|
|
144
|
+
if (err) {
|
|
145
|
+
return callback(null, { code: 503, message: 'Unable to do device lookup.', err });
|
|
146
|
+
}
|
|
147
|
+
for (let i = 0; i < deviceList.length; i += 1) {
|
|
148
|
+
if (results[i] === 'found') {
|
|
149
|
+
findings[deviceList[i]] = true;
|
|
150
|
+
} else { // notfound
|
|
151
|
+
findings[deviceList[i]] = false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
log.debug(`FINDINGS: ${JSON.stringify(findings)}`);
|
|
155
|
+
return callback(findings);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return null; // entity type not cached, exit callback and continue as if cache not enabled
|
|
159
|
+
});
|
|
160
|
+
if (entityTypeCached) {
|
|
161
|
+
return null; // called callback earlier, exit function
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// manual - no cache
|
|
166
|
+
findings = deviceList.reduce((map, device) => {
|
|
167
|
+
// eslint-disable-next-line no-param-reassign
|
|
168
|
+
map[device] = false;
|
|
169
|
+
log.debug(`In reduce: ${JSON.stringify(map)}`);
|
|
170
|
+
return map;
|
|
171
|
+
}, {});
|
|
172
|
+
const apiCalls = deviceList.map((device) => new Promise((resolve) => {
|
|
173
|
+
this.getDevice(device, (result, error) => {
|
|
174
|
+
if (error) {
|
|
175
|
+
log.debug(`In map error: ${JSON.stringify(device)}`);
|
|
176
|
+
return resolve({ name: device, found: false });
|
|
177
|
+
}
|
|
178
|
+
log.debug(`In map: ${JSON.stringify(device)}`);
|
|
179
|
+
return resolve({ name: device, found: true });
|
|
180
|
+
});
|
|
181
|
+
}));
|
|
182
|
+
return Promise.all(apiCalls).then((results) => {
|
|
183
|
+
results.forEach((device) => {
|
|
184
|
+
findings[device.name] = device.found;
|
|
185
|
+
});
|
|
186
|
+
log.debug(`FINDINGS: ${JSON.stringify(findings)}`);
|
|
187
|
+
log.debug('FINDINGS: ', findings);
|
|
188
|
+
return callback(findings);
|
|
189
|
+
}).catch((errors) => {
|
|
190
|
+
log.error('Unable to do device lookup.');
|
|
191
|
+
return callback(null, { code: 503, message: 'Unable to do device lookup.', error: errors });
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @summary Get Appliance that match the deviceName
|
|
197
|
+
*
|
|
198
|
+
* @function getDevice
|
|
199
|
+
* @param {String} deviceName - the deviceName to find (required)
|
|
200
|
+
*
|
|
201
|
+
* @param {getCallback} callback - a callback function to return the result
|
|
202
|
+
* (appliance) or the error
|
|
203
|
+
*/
|
|
204
|
+
getDevice(deviceName, callback) {
|
|
205
|
+
const meth = 'brokerHandler-getDevice';
|
|
206
|
+
const origin = `${this.myid}-${meth}`;
|
|
207
|
+
log.trace(origin);
|
|
208
|
+
|
|
209
|
+
// make sure we are set up for device broker getDevice
|
|
210
|
+
if (!this.allProps.devicebroker || !this.allProps.devicebroker.getDevice || this.allProps.devicebroker.getDevice.length === 0 || !this.allProps.devicebroker.getDevice[0].path) {
|
|
211
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Missing Properties devicebroker.getDevice.path', null, null, null, null);
|
|
212
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
213
|
+
return callback(null, errorObj);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* HERE IS WHERE YOU VALIDATE DATA */
|
|
217
|
+
if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
|
|
218
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Missing Data', ['deviceName'], null, null, null);
|
|
219
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
220
|
+
return callback(null, errorObj);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
// need to get the device so we can convert the deviceName to an id
|
|
225
|
+
// !! if we can do a lookup by name the getDevicesFiltered may not be necessary
|
|
226
|
+
const opts = {
|
|
227
|
+
filter: {
|
|
228
|
+
name: deviceName
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
return this.getDevicesFiltered(opts, (devs, ferr) => {
|
|
233
|
+
// if we received an error or their is no response on the results return an error
|
|
234
|
+
if (ferr) {
|
|
235
|
+
return callback(null, ferr);
|
|
236
|
+
}
|
|
237
|
+
if (devs.list.length < 1) {
|
|
238
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
|
|
239
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
240
|
+
return callback(null, errorObj);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const callPromises = [];
|
|
244
|
+
for (let i = 0; i < this.allProps.devicebroker.getDevice.length; i += 1) {
|
|
245
|
+
// Perform component calls here.
|
|
246
|
+
callPromises.push(
|
|
247
|
+
new Promise((resolve, reject) => {
|
|
248
|
+
this.requestHandlerInst.iapMakeGenericCall('getDevice', this.allProps.devicebroker.getDevice[i], [devs.list[0]], [deviceName], (callRet, callErr) => {
|
|
249
|
+
// return an error
|
|
250
|
+
if (callErr) {
|
|
251
|
+
reject(callErr);
|
|
252
|
+
} else {
|
|
253
|
+
// return the data
|
|
254
|
+
resolve(callRet);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
})
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// return an array of repsonses
|
|
262
|
+
return Promise.all(callPromises).then((results) => {
|
|
263
|
+
let myResult = {};
|
|
264
|
+
results.forEach((result) => {
|
|
265
|
+
myResult = { ...myResult, ...result };
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
return callback(myResult, null);
|
|
269
|
+
}, (error) => {
|
|
270
|
+
// return the error
|
|
271
|
+
log.error(`Call to Get Device Failed ${JSON.stringify(error)}`);
|
|
272
|
+
return callback(null, error);
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
} catch (ex) {
|
|
276
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Caught Exception', null, null, null, ex);
|
|
277
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
278
|
+
return callback(null, errorObj);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* @summary Get Appliances that match the filter
|
|
284
|
+
*
|
|
285
|
+
* @function getDevicesFiltered
|
|
286
|
+
* @param {Object} options - the data to use to filter the appliances (optional)
|
|
287
|
+
*
|
|
288
|
+
* @param {getCallback} callback - a callback function to return the result
|
|
289
|
+
* (appliances) or the error
|
|
290
|
+
*/
|
|
291
|
+
getDevicesFiltered(options, callback) {
|
|
292
|
+
const meth = 'brokerHandler-getDevicesFiltered';
|
|
293
|
+
const origin = `${this.myid}-${meth}`;
|
|
294
|
+
log.trace(origin);
|
|
295
|
+
|
|
296
|
+
// make sure we are set up for device broker getDevicesFiltered
|
|
297
|
+
if (!this.allProps.devicebroker || !this.allProps.devicebroker.getDevicesFiltered || this.allProps.devicebroker.getDevicesFiltered.length === 0 || !this.allProps.devicebroker.getDevicesFiltered[0].path) {
|
|
298
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Missing Properties devicebroker.getDevicesFiltered.path', null, null, null);
|
|
299
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
300
|
+
return callback(null, errorObj);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// verify the required fields have been provided
|
|
304
|
+
if (options === undefined || options === null || options === '' || options.length === 0) {
|
|
305
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Missing Data', ['options'], null, null, null);
|
|
306
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
307
|
+
return callback(null, errorObj);
|
|
308
|
+
}
|
|
309
|
+
log.debug(`Device Filter Options: ${JSON.stringify(options)}`);
|
|
310
|
+
|
|
311
|
+
if (!(options.start === undefined || options.start === null) && (options.limit === undefined || options.limit === null)) {
|
|
312
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Cannot specify start without limit.', null, null, null);
|
|
313
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
314
|
+
return callback(null, errorObj);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if ((options.start === undefined || options.start === null) && !(options.limit === undefined || options.limit === null)) {
|
|
318
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Cannot specify limit without start.', null, null, null);
|
|
319
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
320
|
+
return callback(null, errorObj);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (typeof options.start === 'string' || typeof options.limit === 'string') {
|
|
324
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Start and Limit must be numbers.', null, null, null);
|
|
325
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
326
|
+
return callback(null, errorObj);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (options.start < 0 || options.limit <= 0) {
|
|
330
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Limit and/or Start value is too low.', null, null, null);
|
|
331
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
332
|
+
return callback(null, errorObj);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// if caching get data from the cache
|
|
336
|
+
if (this.allProps.cache.enabled) { // a bit redundant but just in case errors in cacheHandler
|
|
337
|
+
let entityTypeCached = false;
|
|
338
|
+
this.requestHandlerInst.checkEntityTypeCached('Device', (res, error) => {
|
|
339
|
+
if (error) {
|
|
340
|
+
log.error(`${origin}: cache check failed with error ${error}`);
|
|
341
|
+
// continue as if cache disabled, "try again"
|
|
342
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, error, null, null, null);
|
|
343
|
+
return callback(null, errorObj);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (res) {
|
|
347
|
+
entityTypeCached = true;
|
|
348
|
+
// Retrieve devices from cache
|
|
349
|
+
return this.requestHandlerInst.retrieveEntitiesCache('Device', options, (callRet, callErr) => {
|
|
350
|
+
if (callErr) {
|
|
351
|
+
log.error(callErr);
|
|
352
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, callErr, null, null, null);
|
|
353
|
+
return callback(null, errorObj);
|
|
354
|
+
}
|
|
355
|
+
// return the result
|
|
356
|
+
return callback({ total: callRet.length, list: callRet });
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
return null; // entity type not cached, exit callback and continue as if cache not enabled
|
|
360
|
+
});
|
|
361
|
+
if (entityTypeCached) {
|
|
362
|
+
return null; // called callback earlier, exit function
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
try {
|
|
367
|
+
// const nextToken = options.start;
|
|
368
|
+
// const maxResults = options.limit;
|
|
369
|
+
|
|
370
|
+
// set up the filter of Device Names
|
|
371
|
+
let filterName = [];
|
|
372
|
+
if (options && options.filter && options.filter.name) {
|
|
373
|
+
// when this hack is removed, remove the lint ignore above
|
|
374
|
+
if (Array.isArray(options.filter.name)) {
|
|
375
|
+
// eslint-disable-next-line prefer-destructuring
|
|
376
|
+
filterName = options.filter.name;
|
|
377
|
+
} else {
|
|
378
|
+
filterName = [options.filter.name];
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const callPromises = [];
|
|
383
|
+
for (let i = 0; i < this.allProps.devicebroker.getDevicesFiltered.length; i += 1) {
|
|
384
|
+
// Perform component calls here.
|
|
385
|
+
callPromises.push(
|
|
386
|
+
new Promise((resolve, reject) => {
|
|
387
|
+
this.requestHandlerInst.iapMakeGenericCall('getDevicesFiltered', this.allProps.devicebroker.getDevicesFiltered[i], [{ fake: 'fakedata' }], filterName, (callRet, callErr) => {
|
|
388
|
+
// return an error
|
|
389
|
+
if (callErr) {
|
|
390
|
+
console.debug(`in cache iap call failed with error ${callErr}`);
|
|
391
|
+
reject(callErr);
|
|
392
|
+
} else {
|
|
393
|
+
// return the data
|
|
394
|
+
resolve(callRet);
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
})
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// return an array of repsonses
|
|
402
|
+
return Promise.all(callPromises).then((results) => {
|
|
403
|
+
let myResult = [];
|
|
404
|
+
results.forEach((result) => {
|
|
405
|
+
if (Array.isArray(result)) {
|
|
406
|
+
myResult = [...myResult, ...result];
|
|
407
|
+
} else if (Object.keys(result).length > 0) {
|
|
408
|
+
myResult.push(result);
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
// sort by name property
|
|
413
|
+
if (options && options.sort) {
|
|
414
|
+
myResult.sort((a, b) => {
|
|
415
|
+
if (a.name > b.name) {
|
|
416
|
+
return 1;
|
|
417
|
+
}
|
|
418
|
+
if (a.name < b.name) {
|
|
419
|
+
return -1;
|
|
420
|
+
}
|
|
421
|
+
return 0;
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// pagination: get entities limit*start to limit*(start+1) - 1
|
|
426
|
+
if (myResult.length !== 0 && options && options.start >= 0 && options.limit > 0) {
|
|
427
|
+
const end = Math.min(myResult.length, options.limit * (options.start + 1));
|
|
428
|
+
if (options.limit * options.start >= end) {
|
|
429
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Page number too large for limit size.', null, null, null);
|
|
430
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
431
|
+
return callback(null, errorObj);
|
|
432
|
+
}
|
|
433
|
+
myResult = myResult.slice(options.limit * options.start, end);
|
|
434
|
+
}
|
|
435
|
+
log.debug(`${origin}: Found #${myResult.length} devices.`);
|
|
436
|
+
log.debug(`Devices: ${JSON.stringify(myResult)}`);
|
|
437
|
+
return callback({ total: myResult.length, list: myResult });
|
|
438
|
+
}, (error) => {
|
|
439
|
+
// return the error
|
|
440
|
+
log.error(`Call to get devices Failed: ${JSON.stringify(error)}`);
|
|
441
|
+
return callback(null, error);
|
|
442
|
+
});
|
|
443
|
+
} catch (ex) {
|
|
444
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
|
|
445
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
446
|
+
return callback(null, errorObj);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* @summary Gets the status for the provided appliance
|
|
452
|
+
*
|
|
453
|
+
* @function isAlive
|
|
454
|
+
* @param {String} deviceName - the deviceName of the appliance. (required)
|
|
455
|
+
*
|
|
456
|
+
* @param {configCallback} callback - callback function to return the result
|
|
457
|
+
* (appliance isAlive) or the error
|
|
458
|
+
*/
|
|
459
|
+
isAlive(deviceName, callback) {
|
|
460
|
+
const meth = 'brokerHandler-isAlive';
|
|
461
|
+
const origin = `${this.myid}-${meth}`;
|
|
462
|
+
log.trace(origin);
|
|
463
|
+
|
|
464
|
+
// make sure we are set up for device broker isAlive
|
|
465
|
+
if (!this.allProps.devicebroker || !this.allProps.devicebroker.isAlive || this.allProps.devicebroker.isAlive.length === 0 || !this.allProps.devicebroker.isAlive[0].path) {
|
|
466
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Missing Properties devicebroker.isAlive.path', null, null, null);
|
|
467
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
468
|
+
return callback(null, errorObj);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// verify the required fields have been provided
|
|
472
|
+
if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
|
|
473
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Missing Data', ['deviceName'], null, null, null);
|
|
474
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
475
|
+
return callback(null, errorObj);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
try {
|
|
479
|
+
// need to get the device so we can convert the deviceName to an id
|
|
480
|
+
// !! if we can do a lookup by name the getDevicesFiltered may not be necessary
|
|
481
|
+
const opts = {
|
|
482
|
+
filter: {
|
|
483
|
+
name: deviceName
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
return this.getDevicesFiltered(opts, (devs, ferr) => {
|
|
487
|
+
// if we received an error or their is no response on the results return an error
|
|
488
|
+
if (ferr) {
|
|
489
|
+
return callback(null, ferr);
|
|
490
|
+
}
|
|
491
|
+
if (devs.list.length < 1) {
|
|
492
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
|
|
493
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
494
|
+
return callback(null, errorObj);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
const callPromises = [];
|
|
498
|
+
for (let i = 0; i < this.allProps.devicebroker.isAlive.length; i += 1) {
|
|
499
|
+
// Perform component calls here.
|
|
500
|
+
callPromises.push(
|
|
501
|
+
new Promise((resolve, reject) => {
|
|
502
|
+
this.requestHandlerInst.iapMakeGenericCall('isAlive', this.allProps.devicebroker.isAlive[i], [devs.list[0]], null, (callRet, callErr) => {
|
|
503
|
+
// return an error
|
|
504
|
+
if (callErr) {
|
|
505
|
+
reject(callErr);
|
|
506
|
+
} else {
|
|
507
|
+
// return the data
|
|
508
|
+
resolve(callRet);
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
})
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// return an array of repsonses
|
|
516
|
+
return Promise.all(callPromises).then((results) => {
|
|
517
|
+
let myResult = {};
|
|
518
|
+
results.forEach((result) => {
|
|
519
|
+
myResult = { ...myResult, ...result };
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
let response = true;
|
|
523
|
+
if (myResult.isAlive !== null && myResult.isAlive !== undefined && myResult.isAlive === false) {
|
|
524
|
+
response = false;
|
|
525
|
+
}
|
|
526
|
+
return callback(response);
|
|
527
|
+
}, (error) => {
|
|
528
|
+
// return the error
|
|
529
|
+
log.error(`Call to check device status failed: ${JSON.stringify(error)}`);
|
|
530
|
+
return callback(null, error);
|
|
531
|
+
});
|
|
532
|
+
});
|
|
533
|
+
} catch (ex) {
|
|
534
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Caught Exception', null, null, null, ex);
|
|
535
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
536
|
+
return callback(null, errorObj);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* @summary Gets a config for the provided Appliance
|
|
542
|
+
*
|
|
543
|
+
* @function getConfig
|
|
544
|
+
* @param {String} deviceName - the deviceName of the appliance. (required)
|
|
545
|
+
* @param {String} format - the desired format of the config. (optional)
|
|
546
|
+
*
|
|
547
|
+
* @param {configCallback} callback - callback function to return the result
|
|
548
|
+
* (appliance config) or the error
|
|
549
|
+
*/
|
|
550
|
+
getConfig(deviceName, format, callback) {
|
|
551
|
+
const meth = 'brokerHandler-getConfig';
|
|
552
|
+
const origin = `${this.myid}-${meth}`;
|
|
553
|
+
log.trace(origin);
|
|
554
|
+
|
|
555
|
+
// make sure we are set up for device broker getConfig
|
|
556
|
+
if (!this.allProps.devicebroker || !this.allProps.devicebroker.getConfig || this.allProps.devicebroker.getConfig.length === 0 || !this.allProps.devicebroker.getConfig[0].path) {
|
|
557
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Missing Properties devicebroker.getConfig.path', null, null, null);
|
|
558
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
559
|
+
return callback(null, errorObj);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// verify the required fields have been provided
|
|
563
|
+
if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
|
|
564
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Missing Data', ['deviceName'], null, null, null);
|
|
565
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
566
|
+
return callback(null, errorObj);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
try {
|
|
570
|
+
// need to get the device so we can convert the deviceName to an id
|
|
571
|
+
// !! if we can do a lookup by name the getDevicesFiltered may not be necessary
|
|
572
|
+
const opts = {
|
|
573
|
+
filter: {
|
|
574
|
+
name: deviceName
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
return this.getDevicesFiltered(opts, (devs, ferr) => {
|
|
578
|
+
// if we received an error or their is no response on the results return an error
|
|
579
|
+
if (ferr) {
|
|
580
|
+
return callback(null, ferr);
|
|
581
|
+
}
|
|
582
|
+
if (devs.list.length < 1) {
|
|
583
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
|
|
584
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
585
|
+
return callback(null, errorObj);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
const callPromises = [];
|
|
589
|
+
for (let i = 0; i < this.allProps.devicebroker.getConfig.length; i += 1) {
|
|
590
|
+
// Perform component calls here.
|
|
591
|
+
callPromises.push(
|
|
592
|
+
new Promise((resolve, reject) => {
|
|
593
|
+
this.requestHandlerInst.iapMakeGenericCall('getConfig', this.allProps.devicebroker.getConfig[i], [devs.list[0]], null, (callRet, callErr) => {
|
|
594
|
+
// return an error
|
|
595
|
+
if (callErr) {
|
|
596
|
+
reject(callErr);
|
|
597
|
+
} else {
|
|
598
|
+
// return the data
|
|
599
|
+
resolve(callRet);
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
})
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// return an array of repsonses
|
|
607
|
+
return Promise.all(callPromises).then((results) => {
|
|
608
|
+
let myResult = {};
|
|
609
|
+
results.forEach((result) => {
|
|
610
|
+
if (typeof result === 'string') {
|
|
611
|
+
myResult = { ...myResult, result };
|
|
612
|
+
} else if (Array.isArray(result)) {
|
|
613
|
+
// myResult = result[0]; todo Commented out to resolve lint error, unsure how to fix
|
|
614
|
+
} else {
|
|
615
|
+
myResult = { ...myResult, ...result };
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
// return the result
|
|
620
|
+
const newResponse = {
|
|
621
|
+
response: JSON.stringify(myResult, null, 2)
|
|
622
|
+
};
|
|
623
|
+
return callback(newResponse, null);
|
|
624
|
+
}, (error) => {
|
|
625
|
+
// return the error
|
|
626
|
+
log.error(`Call to Get Config Failed: ${JSON.stringify(error)}`);
|
|
627
|
+
return callback(null, error);
|
|
628
|
+
});
|
|
629
|
+
});
|
|
630
|
+
} catch (ex) {
|
|
631
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Caught Exception', null, null, null, ex);
|
|
632
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
633
|
+
return callback(null, errorObj);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* @summary Gets the device count from the system
|
|
639
|
+
*
|
|
640
|
+
* @function iapGetDeviceCount
|
|
641
|
+
*
|
|
642
|
+
* @param {getCallback} callback - callback function to return the result
|
|
643
|
+
* (count) or the error
|
|
644
|
+
*/
|
|
645
|
+
iapGetDeviceCount(callback) {
|
|
646
|
+
const meth = 'brokerHandler-iapGetDeviceCount';
|
|
647
|
+
const origin = `${this.myid}-${meth}`;
|
|
648
|
+
log.trace(origin);
|
|
649
|
+
|
|
650
|
+
// if caching get data from the cache
|
|
651
|
+
if (this.allProps.cache.enabled) { // a bit redundant but just in case errors in cacheHandler
|
|
652
|
+
let entityTypeCached = false;
|
|
653
|
+
this.requestHandlerInst.checkEntityTypeCached('Device', (res, error) => {
|
|
654
|
+
if (error) {
|
|
655
|
+
// should never reach here
|
|
656
|
+
log.error(`${origin}: cache check failed with error ${error}`);
|
|
657
|
+
// continue as if cache disabled, "try again"
|
|
658
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, error, null, null, null);
|
|
659
|
+
return callback(null, errorObj);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
if (res) {
|
|
663
|
+
entityTypeCached = true;
|
|
664
|
+
// Retrieve devices from cache
|
|
665
|
+
return this.requestHandlerInst.retrieveEntitiesCache('Device', {}, (callRet, callErr) => {
|
|
666
|
+
if (callErr) {
|
|
667
|
+
// MAY WANT TO FORMAT AN ERROR AND RETURN THAT (null, error)
|
|
668
|
+
return callback({ count: -1 });
|
|
669
|
+
}
|
|
670
|
+
// return the result
|
|
671
|
+
return callback({ count: callRet.length });
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
return null; // if res === false then continue as if cache not enabled
|
|
675
|
+
});
|
|
676
|
+
if (entityTypeCached) {
|
|
677
|
+
return null; // called callback earlier
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// make sure we are set up for device broker getCount
|
|
682
|
+
if (!this.allProps.devicebroker || !this.allProps.devicebroker.getCount || this.allProps.devicebroker.getCount.length === 0 || !this.allProps.devicebroker.getCount[0].path) {
|
|
683
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Missing Properties devicebroker.getCount.path', null, null, null);
|
|
684
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
685
|
+
return callback(null, errorObj);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// verify the required fields have been provided
|
|
689
|
+
try {
|
|
690
|
+
const callPromises = [];
|
|
691
|
+
for (let i = 0; i < this.allProps.devicebroker.getCount.length; i += 1) {
|
|
692
|
+
// Perform component calls here.
|
|
693
|
+
callPromises.push(
|
|
694
|
+
new Promise((resolve, reject) => {
|
|
695
|
+
this.requestHandlerInst.iapMakeGenericCall('getCount', this.allProps.devicebroker.getCount[i], [{ fake: 'fakedata' }], null, (callRet, callErr) => {
|
|
696
|
+
// return an error
|
|
697
|
+
if (callErr) {
|
|
698
|
+
reject(callErr);
|
|
699
|
+
} else {
|
|
700
|
+
// return the data
|
|
701
|
+
resolve(callRet);
|
|
702
|
+
}
|
|
703
|
+
});
|
|
704
|
+
})
|
|
705
|
+
);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// return an array of repsonses
|
|
709
|
+
return Promise.all(callPromises).then((results) => {
|
|
710
|
+
let myResult = {};
|
|
711
|
+
results.forEach((result) => {
|
|
712
|
+
myResult = { ...myResult, ...result };
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
// return the result
|
|
716
|
+
return callback({ count: Object.keys(myResult).length });
|
|
717
|
+
}, (error) => {
|
|
718
|
+
// return the error
|
|
719
|
+
log.error(`Call to Get Device Count Failed: ${JSON.stringify(error)}`);
|
|
720
|
+
return callback(null, error);
|
|
721
|
+
});
|
|
722
|
+
} catch (ex) {
|
|
723
|
+
const errorObj = this.requestHandlerInst.formatErrorObject(this.myid, meth, 'Caught Exception', null, null, null, ex);
|
|
724
|
+
log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
|
|
725
|
+
return callback(null, errorObj);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
module.exports = BrokerHandler;
|