@arisan/data-api
Version:
The Universal Database API Gateway for CLIO's Modules
246 lines (215 loc) • 9.71 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.logger = undefined;
var _express = require('express');
var _express2 = _interopRequireDefault(_express);
var _moment = require('moment');
var _moment2 = _interopRequireDefault(_moment);
var _mongodb = require('mongodb');
var _mongodb2 = _interopRequireDefault(_mongodb);
var _os = require('os');
var _os2 = _interopRequireDefault(_os);
var _winston = require('winston');
var _winston2 = _interopRequireDefault(_winston);
require('winston-daily-rotate-file');
require('winston-loggly-bulk');
var _LogLevel = require('./LogLevel');
var _LogLevel2 = _interopRequireDefault(_LogLevel);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable import/newline-after-import, import/first */
//region 1. Platform Libraries
const requireAll = require('require-all');
//endregion
//region 2. Project Libraries
//endregion
//region K. Constants
const context = {
heartbeatInterval: null,
logger: null,
routers: null
};
//endregion
//region B. Business Helpers
const timestamp = () => (0, _moment2.default)().format('YYYY-MM-DDTHH:mm:ss.SSSZ');
const formatter = options => {
const timestampPart = `${ options.timestamp() } `;
const levelPart = `${ options.level.toUpperCase() }: `;
const tagPart = options.meta.tags ? `${ options.meta.tags }> ` : '';
const messagePart = options.message || '';
return `${ timestampPart }${ levelPart }${ tagPart }${ messagePart }`;
};
context.logger = function setupDefaultLogger() {
const transports = [new _winston2.default.transports.Console({
formatter,
timestamp
}), new _winston2.default.transports.DailyRotateFile({
datePattern: '.yyyy-MM-dd',
filename: `${ process.cwd() }/data-api.log`,
formatter,
maxFiles: 7,
timestamp
})];
return new _winston2.default.Logger({ transports });
}();
function setupLogger(logLevel, logglySubdomain, logglyToken) {
this.logLevel = _LogLevel2.default[logLevel && logLevel.toUpperCase()] || _LogLevel2.default.DEBUG;
const transports = [new _winston2.default.transports.Console({
formatter,
timestamp
}), new _winston2.default.transports.DailyRotateFile({
datePattern: '.yyyy-MM-dd',
filename: `${ process.cwd() }/data-api.log`,
formatter,
json: false,
maxFiles: 7,
timestamp
})];
if (logglySubdomain && logglySubdomain !== 'null' && logglyToken && logglyToken !== 'null') {
const tags = ['data-api', _os2.default.hostname];
if (this.environment) {
tags.push(this.environment);
}
transports.push(new _winston2.default.transports.Loggly({
formatter,
json: true,
level: this.logLevel.name.toLowerCase(),
subdomain: logglySubdomain,
tags,
timestamp,
token: logglyToken
}));
}
context.logger.configure({
level: this.logLevel.name.toLowerCase(),
transports
});
}
//endregion
//region E. Exports
/**
* Class representing a Data-API
*/
class DataAPI {
constructor() {
this.expressApp = (0, _express2.default)();
}
/**
* Initialize Data-API with options
* @param {object} [options] Options
* @param {string} [options.environment] Environment Tag
* @param {number} [options.heartbeatInterval=10] Heartbeat Interval (s)
* @param {string} [options.logglySubdomain] Loggly Subdomain
* @param {string} [options.logglyToken] Loggly Token
* @param {string} [options.logLevel=DEBUG] Log Level
* @param {string} [options.mongoUrl=mongodb://localhost] MongoDB Connection URL
* @param {number} [options.port=15925] Data-API Port
*/
initialize(options) {
const opts = options || {};
this.environment = opts.environment || '';
setupLogger.bind(this)(opts.logLevel, opts.logglySubdomain, opts.logglyToken);
const log = (lvl, msg) => context.logger.log(lvl, msg, { tags: 'initialize' });
log('debug', 'Initializing....');
if (opts.heartbeatInterval === 0) {
log('error', `Invalid Heartbeat Interval ${ opts.heartbeatInterval }`);
return false;
}
if (opts.mongoUrl && opts.mongoUrl.substring(0, 10) !== 'mongodb://') {
log('error', `Invalid MongoDB Connection URL ${ opts.mongoUrl }`);
return false;
}
if (opts.port < 1 || opts.port > 65535) {
log('error', `Port Number Range Exceeded ${ opts.port }`);
return false;
}
context.heartbeatInterval = opts.heartbeatInterval || 10;
this.mongoUrl = opts.mongoUrl || 'mongodb://localhost';
this.port = opts.port || 15925;
log('info', 'Initialized');
return true;
}
start(callback) {
const log = (lvl, msg) => context.logger.log(lvl, msg, { tags: 'start' });
log('debug', 'Checking existing database connection....');
if (this.database) {
log('error', 'Data API has already been started. Start aborted.');
return false;
}
log('debug', 'Connecting to database....');
_mongodb2.default.connect(this.mongoUrl, (connectErr, connectedDB) => {
if (connectErr) {
log('error', connectErr.message);
return;
}
log('info', 'Database Connected');
this.database = connectedDB;
log('debug', 'Mounting routers....');
context.routers = requireAll({
dirname: `${ __dirname }/routers`,
filter: /^((?!spec).)+\.js$/,
map(name, path) {
const filename = path.substring(path.lastIndexOf('/') + 1, path.lastIndexOf('.'));
return name.length === 1 ? filename : name;
}
});
log('debug', Object.keys(context.routers));
Object.keys(context.routers).forEach(router => {
context.routers[router].default({
app: this.expressApp,
database: this.database,
logger: context.logger
});
});
log('info', 'Routers Mounted');
log('debug', 'Launching Data API....');
this.expressServer = this.expressApp.listen(this.port, listenErr => {
if (listenErr) {
log('error', listenErr.message);
return;
}
log('info', `Data API listening on port ${ this.port }`);
if (callback) {
callback();
}
});
});
return true;
}
stop(callback) {
const log = (lvl, msg) => context.logger.log(lvl, msg, { tags: 'stop' });
log('debug', 'Stopping Data API....');
if (!this.expressServer) {
log('info', 'Express Server Already Closed');
if (callback) {
callback();
}
return;
}
this.expressServer.close(() => {
log('info', 'Express Server Closed');
this.expressServer = null;
if (!this.database) {
if (callback) {
callback();
}
return;
}
this.database.close(() => {
log('info', 'Database Closed');
this.database = null;
if (callback) {
callback();
}
});
});
}
static get heartbeatInterval() {
return context.heartbeatInterval;
}
}
exports.default = DataAPI;
const logger = exports.logger = context.logger;
//endregion
//# sourceMappingURL=DataAPI.js.map