@itentialopensource/adapter-meraki 0.8.2 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
package/adapterBase.js CHANGED
@@ -144,6 +144,44 @@ function updatePackage(changes) {
144
144
  return null;
145
145
  }
146
146
 
147
+ /*
148
+ * INTERNAL FUNCTION: get data from source(s) - nested
149
+ */
150
+ function getDataFromSources(loopField, sources) {
151
+ const loopArray = loopField.split('.');
152
+ let fieldValue = loopField;
153
+
154
+ // go through the sources to find the field
155
+ for (let s = 0; s < sources.length; s += 1) {
156
+ let nestedValue = sources[s];
157
+ let found = false;
158
+
159
+ // loops through incase the field is nested
160
+ for (let i = 0; i < loopArray.length; i += 1) {
161
+ // if not nested finds it first pass - otherwise set to new level and loop
162
+ if (Object.hasOwnProperty.call(nestedValue, loopArray[i])) {
163
+ nestedValue = nestedValue[loopArray[i]];
164
+
165
+ // set found if we are at the leaf (going to stop looping)
166
+ if (i + 1 === loopArray.length) {
167
+ found = true;
168
+ }
169
+ } else {
170
+ // not found in source - check next one
171
+ break;
172
+ }
173
+ }
174
+
175
+ // if we found in source - set and no need to check other sources
176
+ if (found) {
177
+ fieldValue = nestedValue;
178
+ break;
179
+ }
180
+ }
181
+
182
+ return fieldValue;
183
+ }
184
+
147
185
  /* GENERAL ADAPTER FUNCTIONS THESE SHOULD NOT BE DIRECTLY MODIFIED */
148
186
  /* IF YOU NEED MODIFICATIONS, REDEFINE THEM IN adapter.js!!! */
149
187
  class AdapterBase extends EventEmitterCl {
@@ -381,6 +419,85 @@ class AdapterBase extends EventEmitterCl {
381
419
  });
382
420
  }
383
421
 
422
+ /**
423
+ * getAllFunctions is used to get all of the exposed function in the adapter
424
+ *
425
+ * @function getAllFunctions
426
+ */
427
+ getAllFunctions() {
428
+ let myfunctions = [];
429
+ let obj = this;
430
+
431
+ // find the functions in this class
432
+ do {
433
+ const l = Object.getOwnPropertyNames(obj)
434
+ .concat(Object.getOwnPropertySymbols(obj).map((s) => s.toString()))
435
+ .sort()
436
+ .filter((p, i, arr) => typeof obj[p] === 'function' && p !== 'constructor' && (i === 0 || p !== arr[i - 1]) && myfunctions.indexOf(p) === -1);
437
+ myfunctions = myfunctions.concat(l);
438
+ }
439
+ while (
440
+ (obj = Object.getPrototypeOf(obj)) && Object.getPrototypeOf(obj)
441
+ );
442
+
443
+ return myfunctions;
444
+ }
445
+
446
+ /**
447
+ * checkActionFiles is used to update the validation of the action files.
448
+ *
449
+ * @function checkActionFiles
450
+ */
451
+ checkActionFiles() {
452
+ const origin = `${this.id}-adapterBase-checkActionFiles`;
453
+ log.trace(origin);
454
+
455
+ // validate the action files for the adapter
456
+ try {
457
+ return this.requestHandlerInst.checkActionFiles();
458
+ } catch (e) {
459
+ return ['Exception increase log level'];
460
+ }
461
+ }
462
+
463
+ /**
464
+ * checkProperties is used to validate the adapter properties.
465
+ *
466
+ * @function checkProperties
467
+ * @param {Object} properties - an object containing all of the properties
468
+ */
469
+ checkProperties(properties) {
470
+ const origin = `${this.myid}-adapterBase-checkProperties`;
471
+ log.trace(origin);
472
+
473
+ // validate the properties for the adapter
474
+ try {
475
+ return this.requestHandlerInst.checkProperties(properties);
476
+ } catch (e) {
477
+ return { exception: 'Exception increase log level' };
478
+ }
479
+ }
480
+
481
+ /**
482
+ * @summary Takes in property text and an encoding/encryption and returns the resulting
483
+ * encoded/encrypted string
484
+ *
485
+ * @function encryptProperty
486
+ * @param {String} property - the property to encrypt
487
+ * @param {String} technique - the technique to use to encrypt
488
+ *
489
+ * @param {Callback} callback - a callback function to return the result
490
+ * Encrypted String or the Error
491
+ */
492
+ encryptProperty(property, technique, callback) {
493
+ const origin = `${this.id}-adapterBase-encryptProperty`;
494
+ log.trace(origin);
495
+
496
+ // Make the call -
497
+ // encryptProperty(property, technique, callback)
498
+ return this.requestHandlerInst.encryptProperty(property, technique, callback);
499
+ }
500
+
384
501
  /**
385
502
  * iapGetAdapterWorkflowFunctions is used to get all of the workflow function in the adapter
386
503
  * @param {array} ignoreThese - additional methods to ignore (optional)
@@ -397,10 +514,7 @@ class AdapterBase extends EventEmitterCl {
397
514
  // got to the second tier (adapterBase)
398
515
  break;
399
516
  }
400
- if (myfunctions[m] !== 'iapHasAdapterEntity' && myfunctions[m] !== 'iapVerifyAdapterCapability'
401
- && myfunctions[m] !== 'iapUpdateAdapterEntityCache' && myfunctions[m] !== 'healthCheck'
402
- && myfunctions[m] !== 'iapGetAdapterWorkflowFunctions'
403
- && !(myfunctions[m].endsWith('Emit') || myfunctions[m].match(/Emit__v[0-9]+/))) {
517
+ if (!(myfunctions[m].endsWith('Emit') || myfunctions[m].match(/Emit__v[0-9]+/))) {
404
518
  let found = false;
405
519
  if (ignoreThese && Array.isArray(ignoreThese)) {
406
520
  for (let i = 0; i < ignoreThese.length; i += 1) {
@@ -799,85 +913,6 @@ class AdapterBase extends EventEmitterCl {
799
913
  }
800
914
  }
801
915
 
802
- /**
803
- * getAllFunctions is used to get all of the exposed function in the adapter
804
- *
805
- * @function getAllFunctions
806
- */
807
- getAllFunctions() {
808
- let myfunctions = [];
809
- let obj = this;
810
-
811
- // find the functions in this class
812
- do {
813
- const l = Object.getOwnPropertyNames(obj)
814
- .concat(Object.getOwnPropertySymbols(obj).map((s) => s.toString()))
815
- .sort()
816
- .filter((p, i, arr) => typeof obj[p] === 'function' && p !== 'constructor' && (i === 0 || p !== arr[i - 1]) && myfunctions.indexOf(p) === -1);
817
- myfunctions = myfunctions.concat(l);
818
- }
819
- while (
820
- (obj = Object.getPrototypeOf(obj)) && Object.getPrototypeOf(obj)
821
- );
822
-
823
- return myfunctions;
824
- }
825
-
826
- /**
827
- * checkActionFiles is used to update the validation of the action files.
828
- *
829
- * @function checkActionFiles
830
- */
831
- checkActionFiles() {
832
- const origin = `${this.id}-adapterBase-checkActionFiles`;
833
- log.trace(origin);
834
-
835
- // validate the action files for the adapter
836
- try {
837
- return this.requestHandlerInst.checkActionFiles();
838
- } catch (e) {
839
- return ['Exception increase log level'];
840
- }
841
- }
842
-
843
- /**
844
- * checkProperties is used to validate the adapter properties.
845
- *
846
- * @function checkProperties
847
- * @param {Object} properties - an object containing all of the properties
848
- */
849
- checkProperties(properties) {
850
- const origin = `${this.myid}-adapterBase-checkProperties`;
851
- log.trace(origin);
852
-
853
- // validate the properties for the adapter
854
- try {
855
- return this.requestHandlerInst.checkProperties(properties);
856
- } catch (e) {
857
- return { exception: 'Exception increase log level' };
858
- }
859
- }
860
-
861
- /**
862
- * @summary Takes in property text and an encoding/encryption and returns the resulting
863
- * encoded/encrypted string
864
- *
865
- * @function encryptProperty
866
- * @param {String} property - the property to encrypt
867
- * @param {String} technique - the technique to use to encrypt
868
- *
869
- * @param {Callback} callback - a callback function to return the result
870
- * Encrypted String or the Error
871
- */
872
- encryptProperty(property, technique, callback) {
873
- const origin = `${this.id}-adapterBase-encryptProperty`;
874
- log.trace(origin);
875
-
876
- // Make the call -
877
- // encryptProperty(property, technique, callback)
878
- return this.requestHandlerInst.encryptProperty(property, technique, callback);
879
- }
880
-
881
916
  /**
882
917
  * @summary take the entities and add them to the cache
883
918
  *
@@ -1029,6 +1064,67 @@ class AdapterBase extends EventEmitterCl {
1029
1064
  }
1030
1065
  }
1031
1066
 
1067
+ /**
1068
+ * @summary Determines if this adapter supports any in a list of entities
1069
+ *
1070
+ * @function hasEntities
1071
+ * @param {String} entityType - the entity type to check for
1072
+ * @param {Array} entityList - the list of entities we are looking for
1073
+ *
1074
+ * @param {Callback} callback - A map where the entity is the key and the
1075
+ * value is true or false
1076
+ */
1077
+ hasEntities(entityType, entityList, callback) {
1078
+ const origin = `${this.id}-adapter-hasEntities`;
1079
+ log.trace(origin);
1080
+
1081
+ switch (entityType) {
1082
+ case 'Device':
1083
+ return this.hasDevices(entityList, callback);
1084
+ default:
1085
+ return callback(null, `${this.id} does not support entity ${entityType}`);
1086
+ }
1087
+ }
1088
+
1089
+ /**
1090
+ * @summary Helper method for hasEntities for the specific device case
1091
+ *
1092
+ * @param {Array} deviceList - array of unique device identifiers
1093
+ * @param {Callback} callback - A map where the device is the key and the
1094
+ * value is true or false
1095
+ */
1096
+ hasDevices(deviceList, callback) {
1097
+ const origin = `${this.id}-adapter-hasDevices`;
1098
+ log.trace(origin);
1099
+
1100
+ const findings = deviceList.reduce((map, device) => {
1101
+ // eslint-disable-next-line no-param-reassign
1102
+ map[device] = false;
1103
+ log.debug(`In reduce: ${JSON.stringify(map)}`);
1104
+ return map;
1105
+ }, {});
1106
+ const apiCalls = deviceList.map((device) => new Promise((resolve) => {
1107
+ this.getDevice(device, (result, error) => {
1108
+ if (error) {
1109
+ log.debug(`In map error: ${JSON.stringify(device)}`);
1110
+ return resolve({ name: device, found: false });
1111
+ }
1112
+ log.debug(`In map: ${JSON.stringify(device)}`);
1113
+ return resolve({ name: device, found: true });
1114
+ });
1115
+ }));
1116
+ Promise.all(apiCalls).then((results) => {
1117
+ results.forEach((device) => {
1118
+ findings[device.name] = device.found;
1119
+ });
1120
+ log.debug(`FINDINGS: ${JSON.stringify(findings)}`);
1121
+ return callback(findings);
1122
+ }).catch((errors) => {
1123
+ log.error('Unable to do device lookup.');
1124
+ return callback(null, { code: 503, message: 'Unable to do device lookup.', error: errors });
1125
+ });
1126
+ }
1127
+
1032
1128
  /**
1033
1129
  * @summary Make one of the needed Broker calls - could be one of many
1034
1130
  *
@@ -1041,7 +1137,7 @@ class AdapterBase extends EventEmitterCl {
1041
1137
  * @param {getCallback} callback - a callback function to return the result of the call
1042
1138
  */
1043
1139
  iapMakeBrokerCall(brokCall, callProps, devResp, filterName, callback) {
1044
- const meth = 'adapter-iapMakeBrokerCall';
1140
+ const meth = 'adapterBase-iapMakeBrokerCall';
1045
1141
  const origin = `${this.id}-${meth}`;
1046
1142
  log.trace(origin);
1047
1143
 
@@ -1063,24 +1159,10 @@ class AdapterBase extends EventEmitterCl {
1063
1159
 
1064
1160
  // get the field from the provided device
1065
1161
  for (let rq = 0; rq < rqKeys.length; rq += 1) {
1066
- // get the request field we are retrieving
1067
- const loopField = callProps.requestFields[rqKeys[rq]];
1068
- const loopArray = loopField.split('.');
1069
- let nestedValue = devResp;
1070
-
1071
- // loops through incase the field is nested
1072
- for (let i = 0; i < loopArray.length; i += 1) {
1073
- if (Object.hasOwnProperty.call(nestedValue, loopArray[i])) {
1074
- nestedValue = nestedValue[loopArray[i]];
1075
- } else {
1076
- // failed to traverse
1077
- nestedValue = loopField;
1078
- break;
1079
- }
1080
- }
1162
+ const fieldValue = getDataFromSources(callProps.requestFields[rqKeys[rq]], devResp);
1081
1163
 
1082
1164
  // put the value into the path - if it has been specified in the path
1083
- uriPath = uriPath.replace(`{${rqKeys[rq]}}`, nestedValue);
1165
+ uriPath = uriPath.replace(`{${rqKeys[rq]}}`, fieldValue);
1084
1166
  }
1085
1167
  }
1086
1168
  }
@@ -1098,27 +1180,13 @@ class AdapterBase extends EventEmitterCl {
1098
1180
  if (devResp !== null && callProps.requestFields && Object.keys(callProps.requestFields).length > 0) {
1099
1181
  const rqKeys = Object.keys(callProps.requestFields);
1100
1182
 
1101
- // get the uuid from the device
1183
+ // get the field from the provided device
1102
1184
  for (let rq = 0; rq < rqKeys.length; rq += 1) {
1103
1185
  if (cpKeys[cp] === rqKeys[rq]) {
1104
- // get the request field we are retrieving
1105
- const loopField = callProps.requestFields[rqKeys[rq]];
1106
- const loopArray = loopField.split('.');
1107
- let nestedValue = devResp;
1108
-
1109
- // loops through incase the field is nested
1110
- for (let i = 0; i < loopArray.length; i += 1) {
1111
- if (Object.hasOwnProperty.call(nestedValue, loopArray[i])) {
1112
- nestedValue = nestedValue[loopArray[i]];
1113
- } else {
1114
- // failed to traverse
1115
- nestedValue = loopField;
1116
- break;
1117
- }
1118
- }
1186
+ const fieldValue = getDataFromSources(callProps.requestFields[rqKeys[rq]], devResp);
1119
1187
 
1120
1188
  // put the value into the query - if it has been specified in the query
1121
- callQuery[cpKeys[cp]] = nestedValue;
1189
+ callQuery[cpKeys[cp]] = fieldValue;
1122
1190
  }
1123
1191
  }
1124
1192
  }
@@ -1173,38 +1241,25 @@ class AdapterBase extends EventEmitterCl {
1173
1241
  const thisDevice = result.response[a];
1174
1242
  for (let rf = 0; rf < rfKeys.length; rf += 1) {
1175
1243
  if (rfKeys[rf] !== 'ostypePrefix') {
1176
- // get the response field we are retrieving
1177
- const loopField = callProps.responseFields[rfKeys[rf]];
1178
- const loopArray = loopField.split('.');
1179
- let nestedValue = thisDevice;
1180
-
1181
- // loops through incase the field is nested
1182
- for (let i = 0; i < loopArray.length; i += 1) {
1183
- if (Object.hasOwnProperty.call(nestedValue, loopArray[i])) {
1184
- nestedValue = nestedValue[loopArray[i]];
1185
- } else {
1186
- // failed to traverse
1187
- nestedValue = '';
1188
- break;
1189
- }
1190
- }
1244
+ let fieldValue = getDataFromSources(callProps.responseFields[rfKeys[rf]], [thisDevice, devResp, callProps.requestFields]);
1245
+
1191
1246
  // if the field is ostype - need to add prefix
1192
- if (rfKeys[rf] === 'ostype' && typeof nestedValue === 'string') {
1193
- nestedValue = ostypePrefix + nestedValue;
1247
+ if (rfKeys[rf] === 'ostype' && typeof fieldValue === 'string') {
1248
+ fieldValue = ostypePrefix + fieldValue;
1194
1249
  }
1195
1250
  // if there is a status to set, set it
1196
1251
  if (rfKeys[rf] === 'status') {
1197
1252
  // if really looking for just a good response
1198
- if (loopField === 'return2xx' && result.icode === statusValue.toString()) {
1253
+ if (callProps.responseFields[rfKeys[rf]] === 'return2xx' && result.icode === statusValue.toString()) {
1199
1254
  thisDevice.isAlive = true;
1200
- } else if (nestedValue.toString() === statusValue.toString()) {
1255
+ } else if (fieldValue.toString() === statusValue.toString()) {
1201
1256
  thisDevice.isAlive = true;
1202
1257
  } else {
1203
1258
  thisDevice.isAlive = false;
1204
1259
  }
1205
1260
  }
1206
1261
  // if we found a good value
1207
- thisDevice[rfKeys[rf]] = nestedValue;
1262
+ thisDevice[rfKeys[rf]] = fieldValue;
1208
1263
  }
1209
1264
  }
1210
1265
 
@@ -1236,38 +1291,25 @@ class AdapterBase extends EventEmitterCl {
1236
1291
  for (let rf = 0; rf < rfKeys.length; rf += 1) {
1237
1292
  // skip ostypePrefix since it is not a field
1238
1293
  if (rfKeys[rf] !== 'ostypePrefix') {
1239
- // get the response field we are retrieving
1240
- const loopField = callProps.responseFields[rfKeys[rf]];
1241
- const loopArray = loopField.split('.');
1242
- let nestedValue = thisDevice;
1243
-
1244
- // loops through incase the field is nested
1245
- for (let i = 0; i < loopArray.length; i += 1) {
1246
- if (Object.hasOwnProperty.call(nestedValue, loopArray[i])) {
1247
- nestedValue = nestedValue[loopArray[i]];
1248
- } else {
1249
- // failed to traverse
1250
- nestedValue = '';
1251
- break;
1252
- }
1253
- }
1294
+ let fieldValue = getDataFromSources(callProps.responseFields[rfKeys[rf]], [thisDevice, devResp, callProps.requestFields]);
1295
+
1254
1296
  // if the field is ostype - need to add prefix
1255
- if (rfKeys[rf] === 'ostype' && typeof nestedValue === 'string') {
1256
- nestedValue = ostypePrefix + nestedValue;
1297
+ if (rfKeys[rf] === 'ostype' && typeof fieldValue === 'string') {
1298
+ fieldValue = ostypePrefix + fieldValue;
1257
1299
  }
1258
1300
  // if there is a status to set, set it
1259
1301
  if (rfKeys[rf] === 'status') {
1260
1302
  // if really looking for just a good response
1261
- if (loopField === 'return2xx' && result.icode === statusValue.toString()) {
1303
+ if (callProps.responseFields[rfKeys[rf]] === 'return2xx' && result.icode === statusValue.toString()) {
1262
1304
  thisDevice.isAlive = true;
1263
- } else if (nestedValue.toString() === statusValue.toString()) {
1305
+ } else if (fieldValue.toString() === statusValue.toString()) {
1264
1306
  thisDevice.isAlive = true;
1265
1307
  } else {
1266
1308
  thisDevice.isAlive = false;
1267
1309
  }
1268
1310
  }
1269
1311
  // if we found a good value
1270
- thisDevice[rfKeys[rf]] = nestedValue;
1312
+ thisDevice[rfKeys[rf]] = fieldValue;
1271
1313
  }
1272
1314
  }
1273
1315
 
@@ -1294,6 +1336,414 @@ class AdapterBase extends EventEmitterCl {
1294
1336
  return callback(null, errorObj);
1295
1337
  }
1296
1338
  }
1339
+
1340
+ /**
1341
+ * @summary Get Appliance that match the deviceName
1342
+ *
1343
+ * @function getDevice
1344
+ * @param {String} deviceName - the deviceName to find (required)
1345
+ *
1346
+ * @param {getCallback} callback - a callback function to return the result
1347
+ * (appliance) or the error
1348
+ */
1349
+ getDevice(deviceName, callback) {
1350
+ const meth = 'adapterBase-getDevice';
1351
+ const origin = `${this.id}-${meth}`;
1352
+ log.trace(origin);
1353
+
1354
+ // make sure we are set up for device broker getDevice
1355
+ if (!this.allProps.devicebroker || !this.allProps.devicebroker.getDevice || this.allProps.devicebroker.getDevice.length === 0 || !this.allProps.devicebroker.getDevice[0].path) {
1356
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getDevice.path'], null, null, null);
1357
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1358
+ return callback(null, errorObj);
1359
+ }
1360
+
1361
+ /* HERE IS WHERE YOU VALIDATE DATA */
1362
+ if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
1363
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['deviceName'], null, null, null);
1364
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1365
+ return callback(null, errorObj);
1366
+ }
1367
+
1368
+ try {
1369
+ // need to get the device so we can convert the deviceName to an id
1370
+ // !! if we can do a lookup by name the getDevicesFiltered may not be necessary
1371
+ const opts = {
1372
+ filter: {
1373
+ name: deviceName
1374
+ }
1375
+ };
1376
+ return this.getDevicesFiltered(opts, (devs, ferr) => {
1377
+ // if we received an error or their is no response on the results return an error
1378
+ if (ferr) {
1379
+ return callback(null, ferr);
1380
+ }
1381
+ if (devs.list.length < 1) {
1382
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
1383
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1384
+ return callback(null, errorObj);
1385
+ }
1386
+
1387
+ const callPromises = [];
1388
+ for (let i = 0; i < this.allProps.devicebroker.getDevice.length; i += 1) {
1389
+ // Perform component calls here.
1390
+ callPromises.push(
1391
+ new Promise((resolve, reject) => {
1392
+ this.iapMakeBrokerCall('getDevice', this.allProps.devicebroker.getDevice[i], [devs.list[0]], null, (callRet, callErr) => {
1393
+ // return an error
1394
+ if (callErr) {
1395
+ reject(callErr);
1396
+ } else {
1397
+ // return the data
1398
+ resolve(callRet);
1399
+ }
1400
+ });
1401
+ })
1402
+ );
1403
+ }
1404
+
1405
+ // return an array of repsonses
1406
+ return Promise.all(callPromises).then((results) => {
1407
+ let myResult = {};
1408
+ results.forEach((result) => {
1409
+ myResult = { ...myResult, ...result };
1410
+ });
1411
+
1412
+ return callback(myResult, null);
1413
+ });
1414
+ });
1415
+ } catch (ex) {
1416
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1417
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1418
+ return callback(null, errorObj);
1419
+ }
1420
+ }
1421
+
1422
+ /**
1423
+ * @summary Get Appliances that match the filter
1424
+ *
1425
+ * @function getDevicesFiltered
1426
+ * @param {Object} options - the data to use to filter the appliances (optional)
1427
+ *
1428
+ * @param {getCallback} callback - a callback function to return the result
1429
+ * (appliances) or the error
1430
+ */
1431
+ getDevicesFiltered(options, callback) {
1432
+ const meth = 'adapterBase-getDevicesFiltered';
1433
+ const origin = `${this.id}-${meth}`;
1434
+ log.trace(origin);
1435
+
1436
+ // make sure we are set up for device broker getDevicesFiltered
1437
+ if (!this.allProps.devicebroker || !this.allProps.devicebroker.getDevicesFiltered || this.allProps.devicebroker.getDevicesFiltered.length === 0 || !this.allProps.devicebroker.getDevicesFiltered[0].path) {
1438
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getDevicesFiltered.path'], null, null, null);
1439
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1440
+ return callback(null, errorObj);
1441
+ }
1442
+
1443
+ // verify the required fields have been provided
1444
+ if (options === undefined || options === null || options === '' || options.length === 0) {
1445
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['options'], null, null, null);
1446
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1447
+ return callback(null, errorObj);
1448
+ }
1449
+ log.debug(`Device Filter Options: ${JSON.stringify(options)}`);
1450
+
1451
+ try {
1452
+ // TODO - get pagination working
1453
+ // const nextToken = options.start;
1454
+ // const maxResults = options.limit;
1455
+
1456
+ // set up the filter of Device Names
1457
+ let filterName = [];
1458
+ if (options && options.filter && options.filter.name) {
1459
+ // when this hack is removed, remove the lint ignore above
1460
+ if (Array.isArray(options.filter.name)) {
1461
+ // eslint-disable-next-line prefer-destructuring
1462
+ filterName = options.filter.name;
1463
+ } else {
1464
+ filterName = [options.filter.name];
1465
+ }
1466
+ }
1467
+
1468
+ // TODO - get sort and order working
1469
+ /*
1470
+ if (options && options.sort) {
1471
+ reqObj.uriOptions.sort = JSON.stringify(options.sort);
1472
+ }
1473
+ if (options && options.order) {
1474
+ reqObj.uriOptions.order = options.order;
1475
+ }
1476
+ */
1477
+ const callPromises = [];
1478
+ for (let i = 0; i < this.allProps.devicebroker.getDevicesFiltered.length; i += 1) {
1479
+ // Perform component calls here.
1480
+ callPromises.push(
1481
+ new Promise((resolve, reject) => {
1482
+ this.iapMakeBrokerCall('getDevicesFiltered', this.allProps.devicebroker.getDevicesFiltered[i], [{ fake: 'fakedata' }], filterName, (callRet, callErr) => {
1483
+ // return an error
1484
+ if (callErr) {
1485
+ reject(callErr);
1486
+ } else {
1487
+ // return the data
1488
+ resolve(callRet);
1489
+ }
1490
+ });
1491
+ })
1492
+ );
1493
+ }
1494
+
1495
+ // return an array of repsonses
1496
+ return Promise.all(callPromises).then((results) => {
1497
+ let myResult = [];
1498
+ results.forEach((result) => {
1499
+ if (Array.isArray(result)) {
1500
+ myResult = [...myResult, ...result];
1501
+ } else if (Object.keys(result).length > 0) {
1502
+ myResult.push(result);
1503
+ }
1504
+ });
1505
+
1506
+ log.debug(`${origin}: Found #${myResult.length} devices.`);
1507
+ log.debug(`Devices: ${JSON.stringify(myResult)}`);
1508
+ return callback({ total: myResult.length, list: myResult });
1509
+ });
1510
+ } catch (ex) {
1511
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1512
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1513
+ return callback(null, errorObj);
1514
+ }
1515
+ }
1516
+
1517
+ /**
1518
+ * @summary Gets the status for the provided appliance
1519
+ *
1520
+ * @function isAlive
1521
+ * @param {String} deviceName - the deviceName of the appliance. (required)
1522
+ *
1523
+ * @param {configCallback} callback - callback function to return the result
1524
+ * (appliance isAlive) or the error
1525
+ */
1526
+ isAlive(deviceName, callback) {
1527
+ const meth = 'adapterBase-isAlive';
1528
+ const origin = `${this.id}-${meth}`;
1529
+ log.trace(origin);
1530
+
1531
+ // make sure we are set up for device broker isAlive
1532
+ if (!this.allProps.devicebroker || !this.allProps.devicebroker.isAlive || this.allProps.devicebroker.isAlive.length === 0 || !this.allProps.devicebroker.isAlive[0].path) {
1533
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.isAlive.path'], null, null, null);
1534
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1535
+ return callback(null, errorObj);
1536
+ }
1537
+
1538
+ // verify the required fields have been provided
1539
+ if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
1540
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['deviceName'], null, null, null);
1541
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1542
+ return callback(null, errorObj);
1543
+ }
1544
+
1545
+ try {
1546
+ // need to get the device so we can convert the deviceName to an id
1547
+ // !! if we can do a lookup by name the getDevicesFiltered may not be necessary
1548
+ const opts = {
1549
+ filter: {
1550
+ name: deviceName
1551
+ }
1552
+ };
1553
+ return this.getDevicesFiltered(opts, (devs, ferr) => {
1554
+ // if we received an error or their is no response on the results return an error
1555
+ if (ferr) {
1556
+ return callback(null, ferr);
1557
+ }
1558
+ if (devs.list.length < 1) {
1559
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
1560
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1561
+ return callback(null, errorObj);
1562
+ }
1563
+
1564
+ const callPromises = [];
1565
+ for (let i = 0; i < this.allProps.devicebroker.isAlive.length; i += 1) {
1566
+ // Perform component calls here.
1567
+ callPromises.push(
1568
+ new Promise((resolve, reject) => {
1569
+ this.iapMakeBrokerCall('isAlive', this.allProps.devicebroker.isAlive[i], [devs.list[0]], null, (callRet, callErr) => {
1570
+ // return an error
1571
+ if (callErr) {
1572
+ reject(callErr);
1573
+ } else {
1574
+ // return the data
1575
+ resolve(callRet);
1576
+ }
1577
+ });
1578
+ })
1579
+ );
1580
+ }
1581
+
1582
+ // return an array of repsonses
1583
+ return Promise.all(callPromises).then((results) => {
1584
+ let myResult = {};
1585
+ results.forEach((result) => {
1586
+ myResult = { ...myResult, ...result };
1587
+ });
1588
+
1589
+ let response = true;
1590
+ if (myResult.isAlive !== null && myResult.isAlive !== undefined && myResult.isAlive === false) {
1591
+ response = false;
1592
+ }
1593
+ return callback(response);
1594
+ });
1595
+ });
1596
+ } catch (ex) {
1597
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1598
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1599
+ return callback(null, errorObj);
1600
+ }
1601
+ }
1602
+
1603
+ /**
1604
+ * @summary Gets a config for the provided Appliance
1605
+ *
1606
+ * @function getConfig
1607
+ * @param {String} deviceName - the deviceName of the appliance. (required)
1608
+ * @param {String} format - the desired format of the config. (optional)
1609
+ *
1610
+ * @param {configCallback} callback - callback function to return the result
1611
+ * (appliance config) or the error
1612
+ */
1613
+ getConfig(deviceName, format, callback) {
1614
+ const meth = 'adapterBase-getConfig';
1615
+ const origin = `${this.id}-${meth}`;
1616
+ log.trace(origin);
1617
+
1618
+ // make sure we are set up for device broker getConfig
1619
+ if (!this.allProps.devicebroker || !this.allProps.devicebroker.getConfig || this.allProps.devicebroker.getConfig.length === 0 || !this.allProps.devicebroker.getConfig[0].path) {
1620
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getConfig.path'], null, null, null);
1621
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1622
+ return callback(null, errorObj);
1623
+ }
1624
+
1625
+ // verify the required fields have been provided
1626
+ if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
1627
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['deviceName'], null, null, null);
1628
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1629
+ return callback(null, errorObj);
1630
+ }
1631
+
1632
+ try {
1633
+ // need to get the device so we can convert the deviceName to an id
1634
+ // !! if we can do a lookup by name the getDevicesFiltered may not be necessary
1635
+ const opts = {
1636
+ filter: {
1637
+ name: deviceName
1638
+ }
1639
+ };
1640
+ return this.getDevicesFiltered(opts, (devs, ferr) => {
1641
+ // if we received an error or their is no response on the results return an error
1642
+ if (ferr) {
1643
+ return callback(null, ferr);
1644
+ }
1645
+ if (devs.list.length < 1) {
1646
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
1647
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1648
+ return callback(null, errorObj);
1649
+ }
1650
+
1651
+ const callPromises = [];
1652
+ for (let i = 0; i < this.allProps.devicebroker.getConfig.length; i += 1) {
1653
+ // Perform component calls here.
1654
+ callPromises.push(
1655
+ new Promise((resolve, reject) => {
1656
+ this.iapMakeBrokerCall('getConfig', this.allProps.devicebroker.getConfig[i], [devs.list[0]], null, (callRet, callErr) => {
1657
+ // return an error
1658
+ if (callErr) {
1659
+ reject(callErr);
1660
+ } else {
1661
+ // return the data
1662
+ resolve(callRet);
1663
+ }
1664
+ });
1665
+ })
1666
+ );
1667
+ }
1668
+
1669
+ // return an array of repsonses
1670
+ return Promise.all(callPromises).then((results) => {
1671
+ let myResult = {};
1672
+ results.forEach((result) => {
1673
+ myResult = { ...myResult, ...result };
1674
+ });
1675
+
1676
+ // return the result
1677
+ const newResponse = {
1678
+ response: JSON.stringify(myResult, null, 2)
1679
+ };
1680
+ return callback(newResponse, null);
1681
+ });
1682
+ });
1683
+ } catch (ex) {
1684
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1685
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1686
+ return callback(null, errorObj);
1687
+ }
1688
+ }
1689
+
1690
+ /**
1691
+ * @summary Gets the device count from the system
1692
+ *
1693
+ * @function iapGetDeviceCount
1694
+ *
1695
+ * @param {getCallback} callback - callback function to return the result
1696
+ * (count) or the error
1697
+ */
1698
+ iapGetDeviceCount(callback) {
1699
+ const meth = 'adapterBase-iapGetDeviceCount';
1700
+ const origin = `${this.id}-${meth}`;
1701
+ log.trace(origin);
1702
+
1703
+ // make sure we are set up for device broker getCount
1704
+ if (!this.allProps.devicebroker || !this.allProps.devicebroker.getCount || this.allProps.devicebroker.getCount.length === 0 || !this.allProps.devicebroker.getCount[0].path) {
1705
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getCount.path'], null, null, null);
1706
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1707
+ return callback(null, errorObj);
1708
+ }
1709
+
1710
+ // verify the required fields have been provided
1711
+
1712
+ try {
1713
+ const callPromises = [];
1714
+ for (let i = 0; i < this.allProps.devicebroker.getCount.length; i += 1) {
1715
+ // Perform component calls here.
1716
+ callPromises.push(
1717
+ new Promise((resolve, reject) => {
1718
+ this.iapMakeBrokerCall('getCount', this.allProps.devicebroker.getCount[i], null, null, (callRet, callErr) => {
1719
+ // return an error
1720
+ if (callErr) {
1721
+ reject(callErr);
1722
+ } else {
1723
+ // return the data
1724
+ resolve(callRet);
1725
+ }
1726
+ });
1727
+ })
1728
+ );
1729
+ }
1730
+
1731
+ // return an array of repsonses
1732
+ return Promise.all(callPromises).then((results) => {
1733
+ let myResult = {};
1734
+ results.forEach((result) => {
1735
+ myResult = { ...myResult, ...result };
1736
+ });
1737
+
1738
+ // return the result
1739
+ return callback({ count: myResult.length });
1740
+ });
1741
+ } catch (ex) {
1742
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1743
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1744
+ return callback(null, errorObj);
1745
+ }
1746
+ }
1297
1747
  }
1298
1748
 
1299
1749
  module.exports = AdapterBase;