@itentialopensource/adapter-meraki 0.8.2 → 0.8.3

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/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;