@chadkluck/cache-data
Version:
Cache data from an API endpoint or application process using AWS S3 and DynamoDb
318 lines (273 loc) • 9.81 kB
JavaScript
/*
* =============================================================================
* Tools
* -----------------------------------------------------------------------------
*
* Tools used for endpoint data access objects (DAOs) and cache-data. These
* tools are also available for other app functionality
*
* Some classes are internal and not exposed via export. Check list of exports
* for available classes and functions.
*
* -----------------------------------------------------------------------------
* Environment Variables used
* -----------------------------------------------------------------------------
*
* This script uses the Node.js environment variable process.env.AWS_REGION if
* present.
*
*/
const { nodeVer, nodeVerMajor, nodeVerMinor, nodeVerMajorMinor } = require('./vars');
const { AWS, AWSXRay } = require('./AWS.classes');
const APIRequest = require("./APIRequest.class");
const RequestInfo = require("./RequestInfo.class");
const ClientRequest = require("./ClientRequest.class");
const ResponseDataModel = require("./ResponseDataModel.class");
const Response = require("./Response.class");
const Timer = require("./Timer.class");
const DebugAndLog = require("./DebugAndLog.class");
const ImmutableObject = require('./ImmutableObject.class');
const jsonGenericResponse = require('./generic.response.json');
const htmlGenericResponse = require('./generic.response.html');
const xmlGenericResponse = require('./generic.response.xml');
const rssGenericResponse = require('./generic.response.rss');
const textGenericResponse = require('./generic.response.text');
const { printMsg, sanitize, obfuscate, hashThisData} = require('./utils');
const { CachedParameterSecrets, CachedParameterSecret, CachedSSMParameter, CachedSecret } = require('./CachedParametersSecrets.classes')
const { Connections, Connection, ConnectionRequest, ConnectionAuthentication } = require('./Connections.classes')
/*
* -----------------------------------------------------------------------------
* Object definitions
* -----------------------------------------------------------------------------
*/
/**
* @typedef ConnectionObject
* @property {object} connection A connection object
* @property {string} connection.method GET or POST
* @property {string} connection.uri the full uri (overrides protocol, host, path, and parameters) ex https://example.com/api/v1/1004/?key=asdf&y=4
* @property {string} connection.protocol https
* @property {string} connection.host host/domain: example.com
* @property {string} connection.path path of the request: /api/v1/1004
* @property {object} connection.parameters parameters for the query string as an object in key/value pairs
* @property {object} connection.headers headers for the request as an object in key/value pairs
* @property {string} connection.body for POST requests, the body
* @property {string} connection.note a note for logging
* @property {object} connection.options https_get options
* @property {number} connection.options.timeout timeout in milliseconds
*/
/* ****************************************************************************
* Configure classes
* ----------------------------------------------------------------------------
*
* Provides base functionality to be extended by a custom Config class in the
* application.
*
*************************************************************************** */
/**
* _ConfigSuperClass needs to be extended by your own Config class definition.
*
* This super class holds common variables and methods that can be used by any
* application. However, each application requires it's own methods and logic
* to init.
*
* Usage: The child class Config should be placed near the top of the script
* file outside of the event handler. It should be global and must be
* initialized.
*
* @example
* class Config extends tools._ConfigSuperClass {
* // your custom class definition including your implementation of .init()
* }
*
* Config.init();
*/
class _ConfigSuperClass {
static _promise = null;
static _connections = null;
static _settings = null;
static settings() {
return _ConfigSuperClass._settings;
};
/**
*
* @returns {Connections}
*/
static connections() {
return _ConfigSuperClass._connections;
};
/**
*
* @param {string} name
* @returns {Connection}
*/
static getConnection(name) {
return _ConfigSuperClass._connections.get(name);
}
/**
*
* @returns {Promise} A promise that resolves when the Config class has finished initializing
*/
static promise() {
return _ConfigSuperClass._promise;
};
/**
* Retrieve all the parameters (listed in const params) from the
* parameter store and parse out the name. Then return the name
* along with their value.
*
* This will automatically decrypt any encrypted values (it will
* leave any String and StringList parameters as their normal,
* unencrypted self (WithDecryption is ignored for them))
*
* @returns {Promise<array>} parameters and their values
*/
static async _getParametersFromStore (parameters) {
let paramstore = {};
/* go through PARAMS and compile all parameters with
their paths pre-pended into a list of names */
const paramNames = function () {
let names = [];
let paths = [];
/* we have two levels to work through, the base path has param names
grouped under it. So get all the names within each base path grouping. */
parameters.forEach(function(item) {
if ("names" in item) {
item.names.forEach(function(p) {
names.push(item.path+p);
});
} else {
paths.push(item.path);
}
});
return { names: names, paths: paths};
};
let request = [];
let pNames = paramNames();
if (pNames.names.length > 0 || pNames.paths.length > 0 ) {
let paramResultsArr = [];
// process all params by name and place promise in results array
if (pNames.names.length > 0) {
// put the list of full path names into query.Names
const query = {
'Names': pNames.names,
'WithDecryption': true
};
DebugAndLog.debug("Param by name query:",query);
// get parameters from query - wait for the promise to resolve
paramResultsArr.push(AWS.ssm.getByName(query));
}
// process all params by path and place each promise into results array
if (pNames.paths.length > 0) {
pNames.paths.forEach( function (path) {
const query = {
'Path': path,
'WithDecryption': true
};
DebugAndLog.debug("Param by path query", query);
paramResultsArr.push(AWS.ssm.getByPath(query));
});
}
// wait for all parameter request promises to resolve then combine
let promiseArray = await Promise.all(paramResultsArr); // wait
let results = [];
promiseArray.forEach( function (result) { // add parameter list in each result promise to an array
results.push.apply(results, result.Parameters);
//DebugAndLog.debug("added results", result.Parameters);
});
//DebugAndLog.debug("Parameters", results );
/* now that the promise has resolved and we've combined them,
crop off the path and store key and value within the group */
results.forEach(param => {
let nameSections = param.Name.split('/'); // get the last part of the name
const name = nameSections.pop(); // return last section and return as variable name
const groupPath = nameSections.join('/')+"/"; // since we removed the last section, join rest together for path
// put the parameter into its group
const obj = parameters.find(o => o.path === groupPath);
const group = obj.group;
if ( !(group in paramstore)) {
paramstore[group] = {};
}
// store key and value
paramstore[group][name] = param.Value;
});
}
// return an array of keys and values
return paramstore;
};
/**
* This is an intermediary wait
* @param {*} parameters
* @returns {Promise<array>} parameters and their values
*/
static async _getParameters(parameters) {
return await this._getParametersFromStore(parameters);
};
/**
* @example
*
* let params = await this._initParameters(
* [
* {
* "group": "appone", // so we can do params.app.authOSTActionsUsername later
* "path": process.env.paramStorePath, // Lambda environment variable
* "names": [
* "authOSTActionsUsername",
* "authOSTActionsPassword",
* "authExLibrisAPIkey",
* "crypt_secureDataKey"
* ]
* }, // OR get all under a single path
* {
* "group": "app", // so we can do params.app.authOSTActionsUsername later
* "path": process.env.paramStorePath // Lambda environment variable
* }
* ]
* );
* @param {array} parameters An array of parameter locations
* @returns {object} Parameters from the parameter store
*/
static async _initParameters(parameters) {
// make the call to get the parameters and wait before proceeding to the return
return await this._getParameters(parameters);
};
static async _initS3File(paths) {
return {};
};
static async _initDynamoDbRecord(query) {
return {};
};
};
module.exports = {
nodeVer,
nodeVerMajor,
nodeVerMinor,
nodeVerMajorMinor,
AWS,
AWSXRay,
APIRequest,
ImmutableObject,
Timer,
DebugAndLog,
Connection,
Connections,
ConnectionRequest,
ConnectionAuthentication,
RequestInfo,
ClientRequest,
ResponseDataModel,
Response,
_ConfigSuperClass,
CachedSSMParameter,
CachedSecret,
CachedParameterSecret,
CachedParameterSecrets,
jsonGenericResponse,
htmlGenericResponse,
rssGenericResponse,
xmlGenericResponse,
textGenericResponse,
printMsg,
sanitize,
obfuscate,
hashThisData
};