@itentialopensource/adapter-dna_center 0.5.7 → 0.6.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/adapterBase.js CHANGED
@@ -13,6 +13,7 @@
13
13
  /* Required libraries. */
14
14
  const fs = require('fs-extra');
15
15
  const path = require('path');
16
+ const jsonQuery = require('json-query');
16
17
  const EventEmitterCl = require('events').EventEmitter;
17
18
  const { execSync } = require('child_process');
18
19
 
@@ -144,6 +145,27 @@ function updatePackage(changes) {
144
145
  return null;
145
146
  }
146
147
 
148
+ /*
149
+ * INTERNAL FUNCTION: get data from source(s) - nested
150
+ */
151
+ function getDataFromSources(loopField, sources) {
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
+ // find the field value using jsonquery
157
+ const nestedValue = jsonQuery(loopField, { data: sources[s] }).value;
158
+
159
+ // if we found in source - set and no need to check other sources
160
+ if (nestedValue) {
161
+ fieldValue = nestedValue;
162
+ break;
163
+ }
164
+ }
165
+
166
+ return fieldValue;
167
+ }
168
+
147
169
  /* GENERAL ADAPTER FUNCTIONS THESE SHOULD NOT BE DIRECTLY MODIFIED */
148
170
  /* IF YOU NEED MODIFICATIONS, REDEFINE THEM IN adapter.js!!! */
149
171
  class AdapterBase extends EventEmitterCl {
@@ -156,7 +178,7 @@ class AdapterBase extends EventEmitterCl {
156
178
  super();
157
179
 
158
180
  // IAP home directory injected by core when running the adapter within IAP
159
- process.env.iap_home = process.argv[3];
181
+ [, , , process.env.iap_home] = process.argv;
160
182
 
161
183
  try {
162
184
  // Capture the adapter id
@@ -381,6 +403,85 @@ class AdapterBase extends EventEmitterCl {
381
403
  });
382
404
  }
383
405
 
406
+ /**
407
+ * getAllFunctions is used to get all of the exposed function in the adapter
408
+ *
409
+ * @function getAllFunctions
410
+ */
411
+ getAllFunctions() {
412
+ let myfunctions = [];
413
+ let obj = this;
414
+
415
+ // find the functions in this class
416
+ do {
417
+ const l = Object.getOwnPropertyNames(obj)
418
+ .concat(Object.getOwnPropertySymbols(obj).map((s) => s.toString()))
419
+ .sort()
420
+ .filter((p, i, arr) => typeof obj[p] === 'function' && p !== 'constructor' && (i === 0 || p !== arr[i - 1]) && myfunctions.indexOf(p) === -1);
421
+ myfunctions = myfunctions.concat(l);
422
+ }
423
+ while (
424
+ (obj = Object.getPrototypeOf(obj)) && Object.getPrototypeOf(obj)
425
+ );
426
+
427
+ return myfunctions;
428
+ }
429
+
430
+ /**
431
+ * checkActionFiles is used to update the validation of the action files.
432
+ *
433
+ * @function checkActionFiles
434
+ */
435
+ checkActionFiles() {
436
+ const origin = `${this.id}-adapterBase-checkActionFiles`;
437
+ log.trace(origin);
438
+
439
+ // validate the action files for the adapter
440
+ try {
441
+ return this.requestHandlerInst.checkActionFiles();
442
+ } catch (e) {
443
+ return ['Exception increase log level'];
444
+ }
445
+ }
446
+
447
+ /**
448
+ * checkProperties is used to validate the adapter properties.
449
+ *
450
+ * @function checkProperties
451
+ * @param {Object} properties - an object containing all of the properties
452
+ */
453
+ checkProperties(properties) {
454
+ const origin = `${this.myid}-adapterBase-checkProperties`;
455
+ log.trace(origin);
456
+
457
+ // validate the properties for the adapter
458
+ try {
459
+ return this.requestHandlerInst.checkProperties(properties);
460
+ } catch (e) {
461
+ return { exception: 'Exception increase log level' };
462
+ }
463
+ }
464
+
465
+ /**
466
+ * @summary Takes in property text and an encoding/encryption and returns the resulting
467
+ * encoded/encrypted string
468
+ *
469
+ * @function encryptProperty
470
+ * @param {String} property - the property to encrypt
471
+ * @param {String} technique - the technique to use to encrypt
472
+ *
473
+ * @param {Callback} callback - a callback function to return the result
474
+ * Encrypted String or the Error
475
+ */
476
+ encryptProperty(property, technique, callback) {
477
+ const origin = `${this.id}-adapterBase-encryptProperty`;
478
+ log.trace(origin);
479
+
480
+ // Make the call -
481
+ // encryptProperty(property, technique, callback)
482
+ return this.requestHandlerInst.encryptProperty(property, technique, callback);
483
+ }
484
+
384
485
  /**
385
486
  * iapGetAdapterWorkflowFunctions is used to get all of the workflow function in the adapter
386
487
  * @param {array} ignoreThese - additional methods to ignore (optional)
@@ -397,10 +498,7 @@ class AdapterBase extends EventEmitterCl {
397
498
  // got to the second tier (adapterBase)
398
499
  break;
399
500
  }
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]+/))) {
501
+ if (!(myfunctions[m].endsWith('Emit') || myfunctions[m].match(/Emit__v[0-9]+/))) {
404
502
  let found = false;
405
503
  if (ignoreThese && Array.isArray(ignoreThese)) {
406
504
  for (let i = 0; i < ignoreThese.length; i += 1) {
@@ -785,99 +883,21 @@ class AdapterBase extends EventEmitterCl {
785
883
  *
786
884
  * @return {Callback} - containing the response from the mongo transaction
787
885
  */
788
- iapMoveAdapterEntitiesToDB(callback) {
886
+ async iapMoveAdapterEntitiesToDB(callback) {
789
887
  const meth = 'adapterBase-iapMoveAdapterEntitiesToDB';
790
888
  const origin = `${this.id}-${meth}`;
791
889
  log.trace(origin);
792
890
 
793
891
  try {
794
- return callback(entitiesToDB.iapMoveAdapterEntitiesToDB(__dirname, { pronghornProps: this.allProps, id: this.id }), null);
892
+ const result = await entitiesToDB.moveEntitiesToDB(__dirname, { pronghornProps: this.allProps, id: this.id });
893
+ return callback(result, null);
795
894
  } catch (err) {
796
895
  const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, err);
797
896
  log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
798
- return callback(null, errorObj);
897
+ return callback(null, err.message);
799
898
  }
800
899
  }
801
900
 
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
901
  /**
882
902
  * @summary take the entities and add them to the cache
883
903
  *
@@ -1029,6 +1049,67 @@ class AdapterBase extends EventEmitterCl {
1029
1049
  }
1030
1050
  }
1031
1051
 
1052
+ /**
1053
+ * @summary Determines if this adapter supports any in a list of entities
1054
+ *
1055
+ * @function hasEntities
1056
+ * @param {String} entityType - the entity type to check for
1057
+ * @param {Array} entityList - the list of entities we are looking for
1058
+ *
1059
+ * @param {Callback} callback - A map where the entity is the key and the
1060
+ * value is true or false
1061
+ */
1062
+ hasEntities(entityType, entityList, callback) {
1063
+ const origin = `${this.id}-adapter-hasEntities`;
1064
+ log.trace(origin);
1065
+
1066
+ switch (entityType) {
1067
+ case 'Device':
1068
+ return this.hasDevices(entityList, callback);
1069
+ default:
1070
+ return callback(null, `${this.id} does not support entity ${entityType}`);
1071
+ }
1072
+ }
1073
+
1074
+ /**
1075
+ * @summary Helper method for hasEntities for the specific device case
1076
+ *
1077
+ * @param {Array} deviceList - array of unique device identifiers
1078
+ * @param {Callback} callback - A map where the device is the key and the
1079
+ * value is true or false
1080
+ */
1081
+ hasDevices(deviceList, callback) {
1082
+ const origin = `${this.id}-adapter-hasDevices`;
1083
+ log.trace(origin);
1084
+
1085
+ const findings = deviceList.reduce((map, device) => {
1086
+ // eslint-disable-next-line no-param-reassign
1087
+ map[device] = false;
1088
+ log.debug(`In reduce: ${JSON.stringify(map)}`);
1089
+ return map;
1090
+ }, {});
1091
+ const apiCalls = deviceList.map((device) => new Promise((resolve) => {
1092
+ this.getDevice(device, (result, error) => {
1093
+ if (error) {
1094
+ log.debug(`In map error: ${JSON.stringify(device)}`);
1095
+ return resolve({ name: device, found: false });
1096
+ }
1097
+ log.debug(`In map: ${JSON.stringify(device)}`);
1098
+ return resolve({ name: device, found: true });
1099
+ });
1100
+ }));
1101
+ Promise.all(apiCalls).then((results) => {
1102
+ results.forEach((device) => {
1103
+ findings[device.name] = device.found;
1104
+ });
1105
+ log.debug(`FINDINGS: ${JSON.stringify(findings)}`);
1106
+ return callback(findings);
1107
+ }).catch((errors) => {
1108
+ log.error('Unable to do device lookup.');
1109
+ return callback(null, { code: 503, message: 'Unable to do device lookup.', error: errors });
1110
+ });
1111
+ }
1112
+
1032
1113
  /**
1033
1114
  * @summary Make one of the needed Broker calls - could be one of many
1034
1115
  *
@@ -1041,7 +1122,7 @@ class AdapterBase extends EventEmitterCl {
1041
1122
  * @param {getCallback} callback - a callback function to return the result of the call
1042
1123
  */
1043
1124
  iapMakeBrokerCall(brokCall, callProps, devResp, filterName, callback) {
1044
- const meth = 'adapter-iapMakeBrokerCall';
1125
+ const meth = 'adapterBase-iapMakeBrokerCall';
1045
1126
  const origin = `${this.id}-${meth}`;
1046
1127
  log.trace(origin);
1047
1128
 
@@ -1063,24 +1144,10 @@ class AdapterBase extends EventEmitterCl {
1063
1144
 
1064
1145
  // get the field from the provided device
1065
1146
  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
- }
1147
+ const fieldValue = getDataFromSources(callProps.requestFields[rqKeys[rq]], devResp);
1081
1148
 
1082
1149
  // put the value into the path - if it has been specified in the path
1083
- uriPath = uriPath.replace(`{${rqKeys[rq]}}`, nestedValue);
1150
+ uriPath = uriPath.replace(`{${rqKeys[rq]}}`, fieldValue);
1084
1151
  }
1085
1152
  }
1086
1153
  }
@@ -1098,27 +1165,13 @@ class AdapterBase extends EventEmitterCl {
1098
1165
  if (devResp !== null && callProps.requestFields && Object.keys(callProps.requestFields).length > 0) {
1099
1166
  const rqKeys = Object.keys(callProps.requestFields);
1100
1167
 
1101
- // get the uuid from the device
1168
+ // get the field from the provided device
1102
1169
  for (let rq = 0; rq < rqKeys.length; rq += 1) {
1103
1170
  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
- }
1171
+ const fieldValue = getDataFromSources(callProps.requestFields[rqKeys[rq]], devResp);
1119
1172
 
1120
1173
  // put the value into the query - if it has been specified in the query
1121
- callQuery[cpKeys[cp]] = nestedValue;
1174
+ callQuery[cpKeys[cp]] = fieldValue;
1122
1175
  }
1123
1176
  }
1124
1177
  }
@@ -1127,9 +1180,51 @@ class AdapterBase extends EventEmitterCl {
1127
1180
  }
1128
1181
  if (callProps.body) {
1129
1182
  callBody = callProps.body;
1183
+
1184
+ // go through the body fields to check for variable values
1185
+ const cbKeys = Object.keys(callBody);
1186
+ for (let cb = 0; cb < cbKeys.length; cb += 1) {
1187
+ if (callBody[cbKeys[cb]].startsWith('{') && callBody[cbKeys[cb]].endsWith('}')) {
1188
+ // make any necessary changes to the query params
1189
+ if (devResp !== null && callProps.requestFields && Object.keys(callProps.requestFields).length > 0) {
1190
+ const rqKeys = Object.keys(callProps.requestFields);
1191
+
1192
+ // get the field from the provided device
1193
+ for (let rq = 0; rq < rqKeys.length; rq += 1) {
1194
+ if (cbKeys[cb] === rqKeys[rq]) {
1195
+ const fieldValue = getDataFromSources(callProps.requestFields[rqKeys[rq]], devResp);
1196
+
1197
+ // put the value into the query - if it has been specified in the query
1198
+ callBody[cbKeys[cb]] = fieldValue;
1199
+ }
1200
+ }
1201
+ }
1202
+ }
1203
+ }
1130
1204
  }
1131
1205
  if (callProps.headers) {
1132
1206
  callHeaders = callProps.headers;
1207
+
1208
+ // go through the body fields to check for variable values
1209
+ const chKeys = Object.keys(callHeaders);
1210
+ for (let ch = 0; ch < chKeys.length; ch += 1) {
1211
+ if (callHeaders[chKeys[ch]].startsWith('{') && callHeaders[chKeys[ch]].endsWith('}')) {
1212
+ // make any necessary changes to the query params
1213
+ if (devResp !== null && callProps.requestFields && Object.keys(callProps.requestFields).length > 0) {
1214
+ const rqKeys = Object.keys(callProps.requestFields);
1215
+
1216
+ // get the field from the provided device
1217
+ for (let rq = 0; rq < rqKeys.length; rq += 1) {
1218
+ if (chKeys[ch] === rqKeys[rq]) {
1219
+ const fieldValue = getDataFromSources(callProps.requestFields[rqKeys[rq]], devResp);
1220
+
1221
+ // put the value into the query - if it has been specified in the query
1222
+ callHeaders[chKeys[ch]] = fieldValue;
1223
+ }
1224
+ }
1225
+ }
1226
+ }
1227
+ }
1133
1228
  }
1134
1229
  if (callProps.handleFailure) {
1135
1230
  handleFail = callProps.handleFailure;
@@ -1160,6 +1255,12 @@ class AdapterBase extends EventEmitterCl {
1160
1255
  return callback({}, null);
1161
1256
  }
1162
1257
 
1258
+ // get the response piece we care about from the response
1259
+ const myResult = result;
1260
+ if (callProps.responseDatakey) {
1261
+ myResult.response = jsonQuery(callProps.responseDatakey, { data: myResult.response }).value;
1262
+ }
1263
+
1163
1264
  // get the keys for the response fields
1164
1265
  let rfKeys = [];
1165
1266
  if (callProps.responseFields && Object.keys(callProps.responseFields).length > 0) {
@@ -1167,44 +1268,31 @@ class AdapterBase extends EventEmitterCl {
1167
1268
  }
1168
1269
 
1169
1270
  // if we got an array returned (e.g. getDevicesFitered)
1170
- if (Array.isArray(result.response)) {
1271
+ if (Array.isArray(myResult.response)) {
1171
1272
  const listDevices = [];
1172
- for (let a = 0; a < result.response.length; a += 1) {
1173
- const thisDevice = result.response[a];
1273
+ for (let a = 0; a < myResult.response.length; a += 1) {
1274
+ const thisDevice = myResult.response[a];
1174
1275
  for (let rf = 0; rf < rfKeys.length; rf += 1) {
1175
1276
  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
- }
1277
+ let fieldValue = getDataFromSources(callProps.responseFields[rfKeys[rf]], [thisDevice, devResp, callProps.requestFields]);
1278
+
1191
1279
  // if the field is ostype - need to add prefix
1192
- if (rfKeys[rf] === 'ostype' && typeof nestedValue === 'string') {
1193
- nestedValue = ostypePrefix + nestedValue;
1280
+ if (rfKeys[rf] === 'ostype' && typeof fieldValue === 'string') {
1281
+ fieldValue = ostypePrefix + fieldValue;
1194
1282
  }
1195
1283
  // if there is a status to set, set it
1196
1284
  if (rfKeys[rf] === 'status') {
1197
1285
  // if really looking for just a good response
1198
- if (loopField === 'return2xx' && result.icode === statusValue.toString()) {
1286
+ if (callProps.responseFields[rfKeys[rf]] === 'return2xx' && myResult.icode === statusValue.toString()) {
1199
1287
  thisDevice.isAlive = true;
1200
- } else if (nestedValue.toString() === statusValue.toString()) {
1288
+ } else if (fieldValue.toString() === statusValue.toString()) {
1201
1289
  thisDevice.isAlive = true;
1202
1290
  } else {
1203
1291
  thisDevice.isAlive = false;
1204
1292
  }
1205
1293
  }
1206
1294
  // if we found a good value
1207
- thisDevice[rfKeys[rf]] = nestedValue;
1295
+ thisDevice[rfKeys[rf]] = fieldValue;
1208
1296
  }
1209
1297
  }
1210
1298
 
@@ -1232,42 +1320,29 @@ class AdapterBase extends EventEmitterCl {
1232
1320
  }
1233
1321
 
1234
1322
  // if this is not an array - just about everything else, just handle as a single object
1235
- let thisDevice = result.response;
1323
+ let thisDevice = myResult.response;
1236
1324
  for (let rf = 0; rf < rfKeys.length; rf += 1) {
1237
1325
  // skip ostypePrefix since it is not a field
1238
1326
  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
- }
1327
+ let fieldValue = getDataFromSources(callProps.responseFields[rfKeys[rf]], [thisDevice, devResp, callProps.requestFields]);
1328
+
1254
1329
  // if the field is ostype - need to add prefix
1255
- if (rfKeys[rf] === 'ostype' && typeof nestedValue === 'string') {
1256
- nestedValue = ostypePrefix + nestedValue;
1330
+ if (rfKeys[rf] === 'ostype' && typeof fieldValue === 'string') {
1331
+ fieldValue = ostypePrefix + fieldValue;
1257
1332
  }
1258
1333
  // if there is a status to set, set it
1259
1334
  if (rfKeys[rf] === 'status') {
1260
1335
  // if really looking for just a good response
1261
- if (loopField === 'return2xx' && result.icode === statusValue.toString()) {
1336
+ if (callProps.responseFields[rfKeys[rf]] === 'return2xx' && myResult.icode === statusValue.toString()) {
1262
1337
  thisDevice.isAlive = true;
1263
- } else if (nestedValue.toString() === statusValue.toString()) {
1338
+ } else if (fieldValue.toString() === statusValue.toString()) {
1264
1339
  thisDevice.isAlive = true;
1265
1340
  } else {
1266
1341
  thisDevice.isAlive = false;
1267
1342
  }
1268
1343
  }
1269
1344
  // if we found a good value
1270
- thisDevice[rfKeys[rf]] = nestedValue;
1345
+ thisDevice[rfKeys[rf]] = fieldValue;
1271
1346
  }
1272
1347
  }
1273
1348
 
@@ -1294,6 +1369,414 @@ class AdapterBase extends EventEmitterCl {
1294
1369
  return callback(null, errorObj);
1295
1370
  }
1296
1371
  }
1372
+
1373
+ /**
1374
+ * @summary Get Appliance that match the deviceName
1375
+ *
1376
+ * @function getDevice
1377
+ * @param {String} deviceName - the deviceName to find (required)
1378
+ *
1379
+ * @param {getCallback} callback - a callback function to return the result
1380
+ * (appliance) or the error
1381
+ */
1382
+ getDevice(deviceName, callback) {
1383
+ const meth = 'adapterBase-getDevice';
1384
+ const origin = `${this.id}-${meth}`;
1385
+ log.trace(origin);
1386
+
1387
+ // make sure we are set up for device broker getDevice
1388
+ if (!this.allProps.devicebroker || !this.allProps.devicebroker.getDevice || this.allProps.devicebroker.getDevice.length === 0 || !this.allProps.devicebroker.getDevice[0].path) {
1389
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getDevice.path'], null, null, null);
1390
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1391
+ return callback(null, errorObj);
1392
+ }
1393
+
1394
+ /* HERE IS WHERE YOU VALIDATE DATA */
1395
+ if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
1396
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['deviceName'], null, null, null);
1397
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1398
+ return callback(null, errorObj);
1399
+ }
1400
+
1401
+ try {
1402
+ // need to get the device so we can convert the deviceName to an id
1403
+ // !! if we can do a lookup by name the getDevicesFiltered may not be necessary
1404
+ const opts = {
1405
+ filter: {
1406
+ name: deviceName
1407
+ }
1408
+ };
1409
+ return this.getDevicesFiltered(opts, (devs, ferr) => {
1410
+ // if we received an error or their is no response on the results return an error
1411
+ if (ferr) {
1412
+ return callback(null, ferr);
1413
+ }
1414
+ if (devs.list.length < 1) {
1415
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
1416
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1417
+ return callback(null, errorObj);
1418
+ }
1419
+
1420
+ const callPromises = [];
1421
+ for (let i = 0; i < this.allProps.devicebroker.getDevice.length; i += 1) {
1422
+ // Perform component calls here.
1423
+ callPromises.push(
1424
+ new Promise((resolve, reject) => {
1425
+ this.iapMakeBrokerCall('getDevice', this.allProps.devicebroker.getDevice[i], [devs.list[0]], null, (callRet, callErr) => {
1426
+ // return an error
1427
+ if (callErr) {
1428
+ reject(callErr);
1429
+ } else {
1430
+ // return the data
1431
+ resolve(callRet);
1432
+ }
1433
+ });
1434
+ })
1435
+ );
1436
+ }
1437
+
1438
+ // return an array of repsonses
1439
+ return Promise.all(callPromises).then((results) => {
1440
+ let myResult = {};
1441
+ results.forEach((result) => {
1442
+ myResult = { ...myResult, ...result };
1443
+ });
1444
+
1445
+ return callback(myResult, null);
1446
+ });
1447
+ });
1448
+ } catch (ex) {
1449
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1450
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1451
+ return callback(null, errorObj);
1452
+ }
1453
+ }
1454
+
1455
+ /**
1456
+ * @summary Get Appliances that match the filter
1457
+ *
1458
+ * @function getDevicesFiltered
1459
+ * @param {Object} options - the data to use to filter the appliances (optional)
1460
+ *
1461
+ * @param {getCallback} callback - a callback function to return the result
1462
+ * (appliances) or the error
1463
+ */
1464
+ getDevicesFiltered(options, callback) {
1465
+ const meth = 'adapterBase-getDevicesFiltered';
1466
+ const origin = `${this.id}-${meth}`;
1467
+ log.trace(origin);
1468
+
1469
+ // make sure we are set up for device broker getDevicesFiltered
1470
+ if (!this.allProps.devicebroker || !this.allProps.devicebroker.getDevicesFiltered || this.allProps.devicebroker.getDevicesFiltered.length === 0 || !this.allProps.devicebroker.getDevicesFiltered[0].path) {
1471
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getDevicesFiltered.path'], null, null, null);
1472
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1473
+ return callback(null, errorObj);
1474
+ }
1475
+
1476
+ // verify the required fields have been provided
1477
+ if (options === undefined || options === null || options === '' || options.length === 0) {
1478
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['options'], null, null, null);
1479
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1480
+ return callback(null, errorObj);
1481
+ }
1482
+ log.debug(`Device Filter Options: ${JSON.stringify(options)}`);
1483
+
1484
+ try {
1485
+ // TODO - get pagination working
1486
+ // const nextToken = options.start;
1487
+ // const maxResults = options.limit;
1488
+
1489
+ // set up the filter of Device Names
1490
+ let filterName = [];
1491
+ if (options && options.filter && options.filter.name) {
1492
+ // when this hack is removed, remove the lint ignore above
1493
+ if (Array.isArray(options.filter.name)) {
1494
+ // eslint-disable-next-line prefer-destructuring
1495
+ filterName = options.filter.name;
1496
+ } else {
1497
+ filterName = [options.filter.name];
1498
+ }
1499
+ }
1500
+
1501
+ // TODO - get sort and order working
1502
+ /*
1503
+ if (options && options.sort) {
1504
+ reqObj.uriOptions.sort = JSON.stringify(options.sort);
1505
+ }
1506
+ if (options && options.order) {
1507
+ reqObj.uriOptions.order = options.order;
1508
+ }
1509
+ */
1510
+ const callPromises = [];
1511
+ for (let i = 0; i < this.allProps.devicebroker.getDevicesFiltered.length; i += 1) {
1512
+ // Perform component calls here.
1513
+ callPromises.push(
1514
+ new Promise((resolve, reject) => {
1515
+ this.iapMakeBrokerCall('getDevicesFiltered', this.allProps.devicebroker.getDevicesFiltered[i], [{ fake: 'fakedata' }], filterName, (callRet, callErr) => {
1516
+ // return an error
1517
+ if (callErr) {
1518
+ reject(callErr);
1519
+ } else {
1520
+ // return the data
1521
+ resolve(callRet);
1522
+ }
1523
+ });
1524
+ })
1525
+ );
1526
+ }
1527
+
1528
+ // return an array of repsonses
1529
+ return Promise.all(callPromises).then((results) => {
1530
+ let myResult = [];
1531
+ results.forEach((result) => {
1532
+ if (Array.isArray(result)) {
1533
+ myResult = [...myResult, ...result];
1534
+ } else if (Object.keys(result).length > 0) {
1535
+ myResult.push(result);
1536
+ }
1537
+ });
1538
+
1539
+ log.debug(`${origin}: Found #${myResult.length} devices.`);
1540
+ log.debug(`Devices: ${JSON.stringify(myResult)}`);
1541
+ return callback({ total: myResult.length, list: myResult });
1542
+ });
1543
+ } catch (ex) {
1544
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1545
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1546
+ return callback(null, errorObj);
1547
+ }
1548
+ }
1549
+
1550
+ /**
1551
+ * @summary Gets the status for the provided appliance
1552
+ *
1553
+ * @function isAlive
1554
+ * @param {String} deviceName - the deviceName of the appliance. (required)
1555
+ *
1556
+ * @param {configCallback} callback - callback function to return the result
1557
+ * (appliance isAlive) or the error
1558
+ */
1559
+ isAlive(deviceName, callback) {
1560
+ const meth = 'adapterBase-isAlive';
1561
+ const origin = `${this.id}-${meth}`;
1562
+ log.trace(origin);
1563
+
1564
+ // make sure we are set up for device broker isAlive
1565
+ if (!this.allProps.devicebroker || !this.allProps.devicebroker.isAlive || this.allProps.devicebroker.isAlive.length === 0 || !this.allProps.devicebroker.isAlive[0].path) {
1566
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.isAlive.path'], null, null, null);
1567
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1568
+ return callback(null, errorObj);
1569
+ }
1570
+
1571
+ // verify the required fields have been provided
1572
+ if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
1573
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['deviceName'], null, null, null);
1574
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1575
+ return callback(null, errorObj);
1576
+ }
1577
+
1578
+ try {
1579
+ // need to get the device so we can convert the deviceName to an id
1580
+ // !! if we can do a lookup by name the getDevicesFiltered may not be necessary
1581
+ const opts = {
1582
+ filter: {
1583
+ name: deviceName
1584
+ }
1585
+ };
1586
+ return this.getDevicesFiltered(opts, (devs, ferr) => {
1587
+ // if we received an error or their is no response on the results return an error
1588
+ if (ferr) {
1589
+ return callback(null, ferr);
1590
+ }
1591
+ if (devs.list.length < 1) {
1592
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
1593
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1594
+ return callback(null, errorObj);
1595
+ }
1596
+
1597
+ const callPromises = [];
1598
+ for (let i = 0; i < this.allProps.devicebroker.isAlive.length; i += 1) {
1599
+ // Perform component calls here.
1600
+ callPromises.push(
1601
+ new Promise((resolve, reject) => {
1602
+ this.iapMakeBrokerCall('isAlive', this.allProps.devicebroker.isAlive[i], [devs.list[0]], null, (callRet, callErr) => {
1603
+ // return an error
1604
+ if (callErr) {
1605
+ reject(callErr);
1606
+ } else {
1607
+ // return the data
1608
+ resolve(callRet);
1609
+ }
1610
+ });
1611
+ })
1612
+ );
1613
+ }
1614
+
1615
+ // return an array of repsonses
1616
+ return Promise.all(callPromises).then((results) => {
1617
+ let myResult = {};
1618
+ results.forEach((result) => {
1619
+ myResult = { ...myResult, ...result };
1620
+ });
1621
+
1622
+ let response = true;
1623
+ if (myResult.isAlive !== null && myResult.isAlive !== undefined && myResult.isAlive === false) {
1624
+ response = false;
1625
+ }
1626
+ return callback(response);
1627
+ });
1628
+ });
1629
+ } catch (ex) {
1630
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1631
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1632
+ return callback(null, errorObj);
1633
+ }
1634
+ }
1635
+
1636
+ /**
1637
+ * @summary Gets a config for the provided Appliance
1638
+ *
1639
+ * @function getConfig
1640
+ * @param {String} deviceName - the deviceName of the appliance. (required)
1641
+ * @param {String} format - the desired format of the config. (optional)
1642
+ *
1643
+ * @param {configCallback} callback - callback function to return the result
1644
+ * (appliance config) or the error
1645
+ */
1646
+ getConfig(deviceName, format, callback) {
1647
+ const meth = 'adapterBase-getConfig';
1648
+ const origin = `${this.id}-${meth}`;
1649
+ log.trace(origin);
1650
+
1651
+ // make sure we are set up for device broker getConfig
1652
+ if (!this.allProps.devicebroker || !this.allProps.devicebroker.getConfig || this.allProps.devicebroker.getConfig.length === 0 || !this.allProps.devicebroker.getConfig[0].path) {
1653
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getConfig.path'], null, null, null);
1654
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1655
+ return callback(null, errorObj);
1656
+ }
1657
+
1658
+ // verify the required fields have been provided
1659
+ if (deviceName === undefined || deviceName === null || deviceName === '' || deviceName.length === 0) {
1660
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Data', ['deviceName'], null, null, null);
1661
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1662
+ return callback(null, errorObj);
1663
+ }
1664
+
1665
+ try {
1666
+ // need to get the device so we can convert the deviceName to an id
1667
+ // !! if we can do a lookup by name the getDevicesFiltered may not be necessary
1668
+ const opts = {
1669
+ filter: {
1670
+ name: deviceName
1671
+ }
1672
+ };
1673
+ return this.getDevicesFiltered(opts, (devs, ferr) => {
1674
+ // if we received an error or their is no response on the results return an error
1675
+ if (ferr) {
1676
+ return callback(null, ferr);
1677
+ }
1678
+ if (devs.list.length < 1) {
1679
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, `Did Not Find Device ${deviceName}`, [], null, null, null);
1680
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1681
+ return callback(null, errorObj);
1682
+ }
1683
+
1684
+ const callPromises = [];
1685
+ for (let i = 0; i < this.allProps.devicebroker.getConfig.length; i += 1) {
1686
+ // Perform component calls here.
1687
+ callPromises.push(
1688
+ new Promise((resolve, reject) => {
1689
+ this.iapMakeBrokerCall('getConfig', this.allProps.devicebroker.getConfig[i], [devs.list[0]], null, (callRet, callErr) => {
1690
+ // return an error
1691
+ if (callErr) {
1692
+ reject(callErr);
1693
+ } else {
1694
+ // return the data
1695
+ resolve(callRet);
1696
+ }
1697
+ });
1698
+ })
1699
+ );
1700
+ }
1701
+
1702
+ // return an array of repsonses
1703
+ return Promise.all(callPromises).then((results) => {
1704
+ let myResult = {};
1705
+ results.forEach((result) => {
1706
+ myResult = { ...myResult, ...result };
1707
+ });
1708
+
1709
+ // return the result
1710
+ const newResponse = {
1711
+ response: JSON.stringify(myResult, null, 2)
1712
+ };
1713
+ return callback(newResponse, null);
1714
+ });
1715
+ });
1716
+ } catch (ex) {
1717
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1718
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1719
+ return callback(null, errorObj);
1720
+ }
1721
+ }
1722
+
1723
+ /**
1724
+ * @summary Gets the device count from the system
1725
+ *
1726
+ * @function iapGetDeviceCount
1727
+ *
1728
+ * @param {getCallback} callback - callback function to return the result
1729
+ * (count) or the error
1730
+ */
1731
+ iapGetDeviceCount(callback) {
1732
+ const meth = 'adapterBase-iapGetDeviceCount';
1733
+ const origin = `${this.id}-${meth}`;
1734
+ log.trace(origin);
1735
+
1736
+ // make sure we are set up for device broker getCount
1737
+ if (!this.allProps.devicebroker || !this.allProps.devicebroker.getCount || this.allProps.devicebroker.getCount.length === 0 || !this.allProps.devicebroker.getCount[0].path) {
1738
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Missing Properties', ['devicebroker.getCount.path'], null, null, null);
1739
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1740
+ return callback(null, errorObj);
1741
+ }
1742
+
1743
+ // verify the required fields have been provided
1744
+
1745
+ try {
1746
+ const callPromises = [];
1747
+ for (let i = 0; i < this.allProps.devicebroker.getCount.length; i += 1) {
1748
+ // Perform component calls here.
1749
+ callPromises.push(
1750
+ new Promise((resolve, reject) => {
1751
+ this.iapMakeBrokerCall('getCount', this.allProps.devicebroker.getCount[i], null, null, (callRet, callErr) => {
1752
+ // return an error
1753
+ if (callErr) {
1754
+ reject(callErr);
1755
+ } else {
1756
+ // return the data
1757
+ resolve(callRet);
1758
+ }
1759
+ });
1760
+ })
1761
+ );
1762
+ }
1763
+
1764
+ // return an array of repsonses
1765
+ return Promise.all(callPromises).then((results) => {
1766
+ let myResult = {};
1767
+ results.forEach((result) => {
1768
+ myResult = { ...myResult, ...result };
1769
+ });
1770
+
1771
+ // return the result
1772
+ return callback({ count: myResult.length });
1773
+ });
1774
+ } catch (ex) {
1775
+ const errorObj = this.requestHandlerInst.formatErrorObject(this.id, meth, 'Caught Exception', null, null, null, ex);
1776
+ log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
1777
+ return callback(null, errorObj);
1778
+ }
1779
+ }
1297
1780
  }
1298
1781
 
1299
1782
  module.exports = AdapterBase;