const util = require('./util');
const Limiter = require('./limiter');
const fs = require('fs');
/**
* A Module to assist the interaction with an xMatters instance.
* @module environments
*/
/**
*
* @typedef module:environments.Log
* @type {Object}
* @property {function} error implements the console.error function if logLevel allows.
* @property {function} info implements the console.info function if logLevel allows.
* @property {function} log implements the console.log function if logLevel allows.
* @property {function} warn implements the console.warn function if logLevel allows.
*/
/**
*
* @typedef module:environments.xMattersEnvironment
* @type {object}
* @property {string} subdomain - xMatters Instance subdomain.
*
* Example: https://SUBDOMAIN.xmatters.com
*
* @property {string} auth - A request auth object.
* @property {string} baseUrl - The base url for the xMatters instance.
* @property {string} limiter - a task limiter for managing the concurrent
* connections with xMatters.
* @property {module:environments.Log} log The logging object used to write to the console at the set loglevel only.
*
* More information is available here: https://github.com/pimterry/loglevel
* @property {Object[]} errors - array of errors that are generated.
* @property {function} logErrors - function to write out errors to the [console] log.
*
*/
/**
* @typedef module:environments.EnvironmentOptions
* @property {string} logLevel The level of logging to output for this environment.<br>
*<br>
* Default 'error'<br><br>
* Set to one of:<br>
* - 'silent': No console logging<br>
* - 'error': Only Errors<br>
* - 'warn': Errors and warnings.<br>
* - 'info': Errors, warnings, and information.<br>
* - 'debug': All console messages.<br>
*
* @property {string} logPath The file path where processing output can be written. Output is always appended.
*
* @property {boolean} readOnly Whether or not writes and deletes are allowed in this environment.<br>
*<br>
* Default: false<br><br>
* Note: util.post() does not abide by this option.<br>
* Set to one of:<br><br>
* - true: Deleting, Updating, and Creating data in xMatters is skipped. returns the intended object as if it was from xMatters.<br>
* - false: All operations are allowed in the xMatters instance.<br>
*
* * @property {boolean} proxy Enable proxy support by configuring this option.<br>
*<br>
* Default: undefined<br><br>
* Example:<br><br>
* proxy: { port: 3123, host: '10.10.2.200' } <br>
* @default {logLevel: 'error', readOnly: false}
*/
/**
*
* Create a representation of an xMatters instance with credentials, url, connection
* management, and logging.
* The returned object is used to perform other operations in xmtoolbox.
*
* @param {string} subdomain - xMatters Instance subdomain.
*
* Example: https://SUBDOMAIN.xmatters.com
*
* @param {string} user - xMatters username or API Key from user with REST Web Service User Role
* @param {string} pass - Password for user, API key secret for API key, OR encryption key for .xmpw password file if file exists. File name: subdomain.xmpw in main directory of project.
*
* Password needs to be an xMatters password. No SSO/SAML passwords.
*
* @param {module:environments.EnvironmentOptions} options
*
*
* @returns {module:environments.xMattersEnvironment}
* @category environments
*/
function create(subdomain, user, pass, options = {}) {
const limiter = new Limiter({
maxConcurrent: parseInt(process.env.MAX_CONCURRENT_CONNECTIONS || 5),
});
if (!subdomain) {
console.error('xMatters subdomain is not defined for environment.');
}
const passFilePath = `${subdomain.toLowerCase()}.xmpw`;
if (fs.existsSync(passFilePath)) {
const keyName = `XM_KEY_${subdomain.toUpperCase().replace(/\-/g, '_')}`;
const key = pass || process.env[keyName];
try {
if (key) {
pass = util.DecryptFromFile(passFilePath, key);
} else {
console.error('No password or key defined for environment.', subdomain);
}
} catch (error) {
console.error(error);
}
}
const auth = { user, pass };
const baseUrl = `https://${subdomain}.xmatters.com`;
const logLevel = options.logLevel || 'error';
const readOnly = options.readOnly || false;
const proxy = options.proxy;
const logPath = options.logPath;
const logStream = logPath ? fs.createWriteStream(logPath, { flags: 'a' }) : undefined;
const output = [];
const errors = [];
function logErrors() {
console.warn(
'env.logErrors() will be removed in future versions. Access env.errors directly for log errors.'
);
errors.map(error => {
console.error(error.message);
});
}
const logLevels = ['silent', 'error', 'warn', 'info', 'debug'];
let logIndex = logLevels.indexOf(logLevel.toLowerCase());
if (typeof logIndex !== 'number') logIndex = 1;
const timestamp = () => '[' + new Date().toISOString() + '] ';
const log = {
error: function () {
const args = Array.prototype.slice.call(arguments);
const e = new Error(args);
if (logStream) logStream.write(timestamp() + e.toString() + '\n');
errors.push(e);
output.push(e.toString());
logIndex >= 1 ? console.error.apply(null, arguments) : () => {};
},
warn:
logIndex >= 2
? function () {
const msg = [].slice.call(arguments).join(' ');
if (logStream) logStream.write(timestamp() + msg + '\n');
output.push(msg) && console.warn.apply(null, arguments);
}
: () => {},
info:
logIndex >= 3
? function () {
const msg = [].slice.call(arguments).join(' ');
if (logStream) logStream.write(timestamp() + msg + '\n');
output.push(msg) && console.info.apply(null, arguments);
}
: () => {},
time: logIndex >= 3 ? console.time : () => {},
timeEnd: logIndex >= 3 ? console.timeEnd : () => {},
log:
logIndex >= 4
? function () {
const msg = [].slice.call(arguments).join(' ');
if (logStream) logStream.write(timestamp() + msg + '\n');
output.push(msg) && console.log.apply(null, arguments);
}
: () => {},
debug:
logIndex >= 4
? function () {
const msg = [].slice.call(arguments).join(' ');
if (logStream) logStream.write(timestamp() + msg + '\n');
output.push(msg) && console.debug.apply(null, arguments);
}
: () => {},
};
if (readOnly) log.info('Environment', subdomain, 'Read-Only Mode');
return {
subdomain,
auth,
baseUrl,
limiter,
log,
errors,
logErrors,
readOnly,
output,
proxy,
options,
};
}
/**
* creates a new environment using existing environment.
* @param {module:environments.xMattersEnvironment} env The xmtoolbox representation of an xMatters instance.
* @returns {module:environments.xMattersEnvironment}
* @category environments
*/
function copy(env) {
const {
subdomain,
auth: { user, pass },
options,
} = env;
return create(subdomain, user, pass, options);
}
module.exports = { create, copy };
Source