From e5c984563ae52b0af0ebb8696942da9867879df8 Mon Sep 17 00:00:00 2001 From: cscatolini Date: Tue, 8 Nov 2016 10:56:10 -0200 Subject: [PATCH] [WIP] Apps CRUD. --- lib/marathon.js | 482 ++++++++++++++++-- lib/marathon.js.map | 2 +- .../20161103221706-creating app model.js | 4 +- package.json | 6 +- src/api/app.js | 29 +- src/api/handlers/app.js | 90 ++++ src/extensions/postgresql.js | 6 +- src/models/index.js | 4 +- test/unit/api/handlers/appTest.js | 145 ++++++ test/unit/common.js | 1 - 10 files changed, 699 insertions(+), 70 deletions(-) create mode 100644 src/api/handlers/app.js create mode 100644 test/unit/api/handlers/appTest.js diff --git a/lib/marathon.js b/lib/marathon.js index a20476d6..ae47d0e2 100644 --- a/lib/marathon.js +++ b/lib/marathon.js @@ -74,7 +74,7 @@ var _start2 = _interopRequireDefault(_start); - var _version = __webpack_require__(13); + var _version = __webpack_require__(15); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -180,33 +180,41 @@ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - var _path = __webpack_require__(8); + var _humps = __webpack_require__(8); + + var _path = __webpack_require__(9); var _path2 = _interopRequireDefault(_path); - var _koa = __webpack_require__(9); + var _koaValidate = __webpack_require__(10); + + var _koaValidate2 = _interopRequireDefault(_koaValidate); + + var _koa = __webpack_require__(11); var _koa2 = _interopRequireDefault(_koa); - var _koaRoute = __webpack_require__(10); + var _koaRoute = __webpack_require__(12); var _koaRoute2 = _interopRequireDefault(_koaRoute); - var _logger = __webpack_require__(11); + var _logger = __webpack_require__(13); var _logger2 = _interopRequireDefault(_logger); - var _healthcheck = __webpack_require__(15); + var _healthcheck = __webpack_require__(17); var _healthcheck2 = _interopRequireDefault(_healthcheck); - var _redis = __webpack_require__(16); + var _app = __webpack_require__(30); - var _postgresql = __webpack_require__(21); + var _redis = __webpack_require__(18); - var _kafkaClient = __webpack_require__(25); + var _postgresql = __webpack_require__(23); - var _kafkaProducer = __webpack_require__(27); + var _kafkaClient = __webpack_require__(27); + + var _kafkaProducer = __webpack_require__(29); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -236,8 +244,16 @@ var self = this; var handlers = []; - // Include handlers here + // Include handlers here in the order the routes are supposed to be handled + // example that will be resolved correctly: + // GET /healthcheck/me + // GET /healthcheck/:param + // example that will be resolved incorrectly: + // GET /healthcheck/:param + // GET /healthcheck/me handlers.push(new _healthcheck2.default(self)); + handlers.push(new _app.AppsHandler(self)); + handlers.push(new _app.AppHandler(self)); return handlers; } @@ -470,6 +486,7 @@ return _ref5.apply(this, arguments); }; }()); + (0, _koaValidate2.default)(this.koaApp); } }, { key: 'initializeApp', @@ -492,7 +509,12 @@ } var handlerMethod = handler[methodName].bind(handler); var method = _koaRoute2.default[methodName]; - _this2.koaApp.use(method(handler.route, function () { + var args = [handler.route]; + var validate = handler[(0, _humps.camelize)('validate_' + methodName)]; + if (validate) { + args.push(validate); + } + args.push(function () { var _ref7 = _asyncToGenerator(regeneratorRuntime.mark(function _callee6(ctx) { return regeneratorRuntime.wrap(function _callee6$(_context6) { while (1) { @@ -512,7 +534,9 @@ return function (_x3) { return _ref7.apply(this, arguments); }; - }())); + }()); + + _this2.koaApp.use(method.apply(handler, args)); }); }); @@ -574,22 +598,34 @@ /* 8 */ /***/ function(module, exports) { - module.exports = require("path"); + module.exports = require("humps"); /***/ }, /* 9 */ /***/ function(module, exports) { - module.exports = require("koa"); + module.exports = require("path"); /***/ }, /* 10 */ /***/ function(module, exports) { - module.exports = require("koa-route"); + module.exports = require("koa-validate"); /***/ }, /* 11 */ +/***/ function(module, exports) { + + module.exports = require("koa"); + +/***/ }, +/* 12 */ +/***/ function(module, exports) { + + module.exports = require("koa-route"); + +/***/ }, +/* 13 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; @@ -600,11 +636,11 @@ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - var _bunyan = __webpack_require__(12); + var _bunyan = __webpack_require__(14); var _bunyan2 = _interopRequireDefault(_bunyan); - var _version = __webpack_require__(13); + var _version = __webpack_require__(15); var _version2 = _interopRequireDefault(_version); @@ -660,13 +696,13 @@ exports.default = Logger; /***/ }, -/* 12 */ +/* 14 */ /***/ function(module, exports) { module.exports = require("bunyan"); /***/ }, -/* 13 */ +/* 15 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; @@ -675,7 +711,7 @@ value: true }); - var _package = __webpack_require__(14); + var _package = __webpack_require__(16); var _package2 = _interopRequireDefault(_package); @@ -686,7 +722,7 @@ exports.default = version; /***/ }, -/* 14 */ +/* 16 */ /***/ function(module, exports) { module.exports = { @@ -738,15 +774,18 @@ "dependencies": { "babel-runtime": "^6.11.6", "bluebird": "^3.4.6", + "boom": "^4.2.0", "bufferutil": "^1.2.1", "bunyan": "^1.8.1", "commander": "^2.9.0", "config": "^1.21.0", + "humps": "^2.0.0", "js-yaml": "^3.6.1", "json-loader": "^0.5.4", "kafka-node": "^1.0.5", "koa": "^2.0.0-alpha.7", "koa-route": "^3.2.0", + "koa-validate": "^1.0.7", "mongoose": "^4.6.5", "pg": "^6.1.0", "pg-hstore": "^2.3.2", @@ -764,7 +803,7 @@ }; /***/ }, -/* 15 */ +/* 17 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; @@ -775,13 +814,13 @@ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - var _redis = __webpack_require__(16); + var _redis = __webpack_require__(18); - var _postgresql = __webpack_require__(21); + var _postgresql = __webpack_require__(23); - var _kafkaClient = __webpack_require__(25); + var _kafkaClient = __webpack_require__(27); - var _kafkaProducer = __webpack_require__(27); + var _kafkaProducer = __webpack_require__(29); function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } @@ -868,7 +907,7 @@ exports.default = HealthcheckHandler; /***/ }, -/* 16 */ +/* 18 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; @@ -1060,19 +1099,19 @@ }; }(); - var _redis = __webpack_require__(17); + var _redis = __webpack_require__(19); var _redis2 = _interopRequireDefault(_redis); - var _bluebird = __webpack_require__(18); + var _bluebird = __webpack_require__(20); var _bluebird2 = _interopRequireDefault(_bluebird); - var _redisInfo = __webpack_require__(19); + var _redisInfo = __webpack_require__(21); var _redisInfo2 = _interopRequireDefault(_redisInfo); - var _redlock = __webpack_require__(20); + var _redlock = __webpack_require__(22); var _redlock2 = _interopRequireDefault(_redlock); @@ -1088,31 +1127,31 @@ var LockTTL = exports.LockTTL = 100; /***/ }, -/* 17 */ +/* 19 */ /***/ function(module, exports) { module.exports = require("redis"); /***/ }, -/* 18 */ +/* 20 */ /***/ function(module, exports) { module.exports = require("bluebird"); /***/ }, -/* 19 */ +/* 21 */ /***/ function(module, exports) { module.exports = require("redis-info"); /***/ }, -/* 20 */ +/* 22 */ /***/ function(module, exports) { module.exports = require("redlock"); /***/ }, -/* 21 */ +/* 23 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; @@ -1261,9 +1300,9 @@ case 10: logr.debug('Loading models...'); - _index2.default.forEach(function (model) { - db[model.name] = model; - logr.debug({ model: model.name }, 'Model loaded successfully.'); + Object.keys(_index2.default).forEach(function (model) { + db[model] = _index2.default[model]; + logr.debug({ model: model }, 'Model loaded successfully.'); }); logr.debug('All models loaded successfully.'); @@ -1325,11 +1364,11 @@ }; }(); - var _sequelize = __webpack_require__(22); + var _sequelize = __webpack_require__(24); var _sequelize2 = _interopRequireDefault(_sequelize); - var _index = __webpack_require__(23); + var _index = __webpack_require__(25); var _index2 = _interopRequireDefault(_index); @@ -1338,13 +1377,13 @@ function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } /***/ }, -/* 22 */ +/* 24 */ /***/ function(module, exports) { module.exports = require("sequelize"); /***/ }, -/* 23 */ +/* 25 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; @@ -1353,22 +1392,24 @@ value: true }); - var _app = __webpack_require__(24); + var _app = __webpack_require__(26); var _app2 = _interopRequireDefault(_app); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - var models = [_app2.default]; + var models = { + App: _app2.default + }; exports.default = models; /***/ }, -/* 24 */ +/* 26 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; - var Sequelize = __webpack_require__(22); + var Sequelize = __webpack_require__(24); module.exports = function (sequelize) { return sequelize.define('app', { @@ -1395,7 +1436,7 @@ }; /***/ }, -/* 25 */ +/* 27 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; @@ -1480,18 +1521,18 @@ }; }(); - var _kafkaNode = __webpack_require__(26); + var _kafkaNode = __webpack_require__(28); function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } /***/ }, -/* 26 */ +/* 28 */ /***/ function(module, exports) { module.exports = require("kafka-node"); /***/ }, -/* 27 */ +/* 29 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; @@ -1586,7 +1627,7 @@ }; }(); - var _kafkaNode = __webpack_require__(26); + var _kafkaNode = __webpack_require__(28); var _kafkaNode2 = _interopRequireDefault(_kafkaNode); @@ -1594,6 +1635,341 @@ function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } +/***/ }, +/* 30 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + Object.defineProperty(exports, "__esModule", { + value: true + }); + + var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + + function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } + + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + + var Boom = __webpack_require__(31); + + var AppsHandler = exports.AppsHandler = function () { + function AppsHandler(app) { + _classCallCheck(this, AppsHandler); + + this.app = app; + this.route = '/apps'; + } + + _createClass(AppsHandler, [{ + key: 'validatePost', + value: function () { + var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(ctx, next) { + var error; + return regeneratorRuntime.wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + this.checkHeaders('user-email').notEmpty().isEmail(); + this.checkQuery('bundleId').notEmpty().match(/^[a-z0-9]+\.[a-z0-9]+(\.[a-z0-9]+)+$/i); + this.checkQuery('key').notEmpty().len(1, 255); + + if (!this.errors) { + _context.next = 9; + break; + } + + error = Boom.badData('wrong arguments', this.errors); + + ctx.status = 422; + ctx.body = error.output.payload; + ctx.body.data = error.data; + return _context.abrupt('return'); + + case 9: + _context.next = 11; + return next; + + case 11: + case 'end': + return _context.stop(); + } + } + }, _callee, this); + })); + + function validatePost(_x, _x2) { + return _ref.apply(this, arguments); + } + + return validatePost; + }() + }, { + key: 'get', + value: function () { + var _ref2 = _asyncToGenerator(regeneratorRuntime.mark(function _callee2(ctx) { + var apps; + return regeneratorRuntime.wrap(function _callee2$(_context2) { + while (1) { + switch (_context2.prev = _context2.next) { + case 0: + _context2.next = 2; + return this.app.db.App.findAll(); + + case 2: + apps = _context2.sent; + + ctx.body = { apps: apps }; + ctx.status = 200; + + case 5: + case 'end': + return _context2.stop(); + } + } + }, _callee2, this); + })); + + function get(_x3) { + return _ref2.apply(this, arguments); + } + + return get; + }() + }, { + key: 'post', + value: function () { + var _ref3 = _asyncToGenerator(regeneratorRuntime.mark(function _callee3(ctx) { + var body, app; + return regeneratorRuntime.wrap(function _callee3$(_context3) { + while (1) { + switch (_context3.prev = _context3.next) { + case 0: + body = this.request.body; + + body.createdBy = this.request.header['user-email']; + _context3.next = 4; + return this.app.db.App.create(body); + + case 4: + app = _context3.sent; + + ctx.body = { app: app }; + ctx.status = 201; + + case 7: + case 'end': + return _context3.stop(); + } + } + }, _callee3, this); + })); + + function post(_x4) { + return _ref3.apply(this, arguments); + } + + return post; + }() + }]); + + return AppsHandler; + }(); + + var AppHandler = exports.AppHandler = function () { + function AppHandler(app) { + _classCallCheck(this, AppHandler); + + this.app = app; + this.route = '/apps/:id'; + } + + _createClass(AppHandler, [{ + key: 'validatePut', + value: function () { + var _ref4 = _asyncToGenerator(regeneratorRuntime.mark(function _callee4(ctx, next) { + var error; + return regeneratorRuntime.wrap(function _callee4$(_context4) { + while (1) { + switch (_context4.prev = _context4.next) { + case 0: + this.checkQuery('bundleId').notEmpty().match(/^[a-z0-9]+\.[a-z0-9]+(\.[a-z0-9]+)+$/i); + this.checkQuery('key').notEmpty().len(1, 255); + + if (!this.errors) { + _context4.next = 8; + break; + } + + error = Boom.badData('wrong arguments', this.errors); + + ctx.status = 422; + ctx.body = error.output.payload; + ctx.body.data = error.data; + return _context4.abrupt('return'); + + case 8: + _context4.next = 10; + return next; + + case 10: + case 'end': + return _context4.stop(); + } + } + }, _callee4, this); + })); + + function validatePut(_x5, _x6) { + return _ref4.apply(this, arguments); + } + + return validatePut; + }() + }, { + key: 'get', + value: function () { + var _ref5 = _asyncToGenerator(regeneratorRuntime.mark(function _callee5(ctx) { + var app; + return regeneratorRuntime.wrap(function _callee5$(_context5) { + while (1) { + switch (_context5.prev = _context5.next) { + case 0: + _context5.next = 2; + return this.app.db.App.findById(this.params.id); + + case 2: + app = _context5.sent; + + if (app) { + _context5.next = 6; + break; + } + + ctx.status = 404; + return _context5.abrupt('return'); + + case 6: + ctx.body = { app: app }; + ctx.status = 200; + + case 8: + case 'end': + return _context5.stop(); + } + } + }, _callee5, this); + })); + + function get(_x7) { + return _ref5.apply(this, arguments); + } + + return get; + }() + }, { + key: 'put', + value: function () { + var _ref6 = _asyncToGenerator(regeneratorRuntime.mark(function _callee6(ctx) { + var body, app, updatedApp; + return regeneratorRuntime.wrap(function _callee6$(_context6) { + while (1) { + switch (_context6.prev = _context6.next) { + case 0: + body = this.request.body; + _context6.next = 3; + return this.app.db.App.findById(this.params.id); + + case 3: + app = _context6.sent; + + if (app) { + _context6.next = 7; + break; + } + + ctx.status = 404; + return _context6.abrupt('return'); + + case 7: + _context6.next = 9; + return app.updateAttributes(body); + + case 9: + updatedApp = _context6.sent; + + ctx.body = { app: updatedApp }; + ctx.status = 200; + + case 12: + case 'end': + return _context6.stop(); + } + } + }, _callee6, this); + })); + + function put(_x8) { + return _ref6.apply(this, arguments); + } + + return put; + }() + }, { + key: 'delete', + value: function () { + var _ref7 = _asyncToGenerator(regeneratorRuntime.mark(function _callee7(ctx) { + var app; + return regeneratorRuntime.wrap(function _callee7$(_context7) { + while (1) { + switch (_context7.prev = _context7.next) { + case 0: + _context7.next = 2; + return this.app.db.App.findById(this.params.id); + + case 2: + app = _context7.sent; + + if (app) { + _context7.next = 6; + break; + } + + ctx.status = 404; + return _context7.abrupt('return'); + + case 6: + _context7.next = 8; + return app.destroy(); + + case 8: + ctx.status = 204; + + case 9: + case 'end': + return _context7.stop(); + } + } + }, _callee7, this); + })); + + function _delete(_x9) { + return _ref7.apply(this, arguments); + } + + return _delete; + }() + }]); + + return AppHandler; + }(); + +/***/ }, +/* 31 */ +/***/ function(module, exports) { + + module.exports = require("boom"); + /***/ } /******/ ]); //# sourceMappingURL=marathon.js.map \ No newline at end of file diff --git a/lib/marathon.js.map b/lib/marathon.js.map index 8270e1d8..6a838e72 100644 --- a/lib/marathon.js.map +++ b/lib/marathon.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack:///webpack/bootstrap c748c493ba2eccd82c8a","webpack:///external \"babel-polyfill\"","webpack:///./src/index.js","webpack:///(webpack)/buildin/module.js","webpack:///external \"commander\"","webpack:///./src/cmd/start.js","webpack:///external \"config\"","webpack:///./src/api/app.js","webpack:///external \"path\"","webpack:///external \"koa\"","webpack:///external \"koa-route\"","webpack:///./src/extensions/logger.js","webpack:///external \"bunyan\"","webpack:///./src/extensions/version.js","webpack:///./package.json","webpack:///./src/api/handlers/healthcheck.js","webpack:///./src/extensions/redis.js","webpack:///external \"redis\"","webpack:///external \"bluebird\"","webpack:///external \"redis-info\"","webpack:///external \"redlock\"","webpack:///./src/extensions/postgresql.js","webpack:///external \"sequelize\"","webpack:///./src/models/index.js","webpack:///./src/models/app.js","webpack:///./src/extensions/kafkaClient.js","webpack:///external \"kafka-node\"","webpack:///./src/extensions/kafkaProducer.js"],"names":["RootCmd","rootCmd","version","args","parse","module","parent","cmd","run","process","argv","StartCmd","command","description","action","app","MarathonApp","config","allowedMethods","koaApp","configureLogger","configureMiddleware","handlersPath","join","__dirname","handlers","getHandlers","redisConfig","get","pgConfig","self","push","err","env","NODE_ENV","logger","fatal","exit","child","source","redisOptions","db","shouldReconnect","password","url","redisClient","options","debug","cfg","clientId","apiKafkaClient","producerCfg","apiKafkaProducer","configureRedis","configurePostgreSQL","configureKafka","use","ctx","next","start","Date","ms","set","initializeServices","forEach","handler","methodName","handlerMethod","bind","method","route","PORT","initializeApp","info","listen","Logger","logLevel","logToStdOut","logToFile","logFile","streams","stream","stdout","level","path","createLogger","name","src","getStreams","serializers","stdSerializers","HealthcheckHandler","resetServices","services","redis","up","postgreSQL","body","JSON","stringify","hasFailed","status","result","error","uptime","connectedClients","blockedClients","usedMemory","totalSystemMemory","maxMemory","rejectedConnections","cpuUsage","infoAsync","res","uptime_in_seconds","connected_clients","blocked_clients","used_memory_human","total_system_memory_human","maxmemory_human","rejected_connections","used_cpu_user","message","check","redisUrl","logr","retry_strategy","undefined","createClient","hasConnected","Promise","resolve","reject","ready","on","Error","pingAsync","connect","f","Lock","retryCount","retryDelay","lock","LockKey","LockTTL","rlock","unlock","withCriticalSection","promisifyAll","RedisClient","prototype","Multi","query","deadlockQuery","client","type","QueryTypes","SELECT","activeOperations","length","deadlock","deadlockOperations","row","blocked","pid","blocked_pid","txId","blocked_transaction_id","user","blocked_user","statement","blocked_statement","blocking","blocking_pid","blocking_transaction_id","blocking_user","blocking_statement","pgUrl","opt","dialect","model","Object","keys","modelName","associate","models","Sequelize","require","exports","sequelize","define","key","STRING","allowNull","validate","len","bundleId","createdBy","timestamps","underscored","indexes","fields","unique","kafkaClient","producer","Producer"],"mappings":"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","file":"marathon.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap c748c493ba2eccd82c8a","module.exports = require(\"babel-polyfill\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"babel-polyfill\"\n// module id = 1\n// module chunks = 0","import program from 'commander'\nimport StartCmd from './cmd/start'\nimport { version } from './extensions/version'\n\nexport default class RootCmd {\n constructor() {\n this.rootCmd = program\n .version(version)\n }\n\n run(args) {\n this.rootCmd.parse(args)\n }\n}\n\nif (!module.parent) {\n const cmd = new RootCmd()\n new StartCmd(cmd.rootCmd) //eslint-disable-line\n cmd.run(process.argv)\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/index.js","module.exports = function(module) {\n\tif(!module.webpackPolyfill) {\n\t\tmodule.deprecate = function() {};\n\t\tmodule.paths = [];\n\t\t// module.parent = undefined by default\n\t\tmodule.children = [];\n\t\tmodule.webpackPolyfill = 1;\n\t}\n\treturn module;\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// (webpack)/buildin/module.js\n// module id = 3\n// module chunks = 0","module.exports = require(\"commander\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"commander\"\n// module id = 4\n// module chunks = 0","import config from 'config'\nimport MarathonApp from '../api/app'\n\nexport default class StartCmd {\n constructor(rootCmd) {\n rootCmd\n .command('start')\n .description('Start API')\n .action(() => {\n const app = new MarathonApp(config)\n app.run()\n })\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/cmd/start.js","module.exports = require(\"config\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"config\"\n// module id = 6\n// module chunks = 0","import path from 'path'\nimport Koa from 'koa'\nimport _ from 'koa-route'\nimport Logger from '../extensions/logger'\nimport HealthcheckHandler from './handlers/healthcheck'\nimport { connect as redisConnect } from '../extensions/redis'\nimport { connect as pgConnect } from '../extensions/postgresql'\nimport { connect as kafkaClientConnect } from '../extensions/kafkaClient'\nimport { connect as kafkaProducerConnect } from '../extensions/kafkaProducer'\n\n\nexport default class MarathonApp {\n constructor(config) {\n this.config = config\n this.allowedMethods = ['get', 'post', 'put', 'delete']\n this.koaApp = new Koa()\n this.configureLogger()\n this.configureMiddleware()\n\n this.handlersPath = path.join(__dirname, '../api/handlers')\n this.handlers = this.getHandlers()\n this.redisConfig = config.get('app.services.redis')\n this.pgConfig = config.get('app.services.postgresql')\n }\n\n getHandlers() {\n const self = this\n const handlers = []\n\n // Include handlers here\n handlers.push(new HealthcheckHandler(self))\n\n return handlers\n }\n\n exit(err) {\n if (process.env.NODE_ENV === 'test') {\n throw err\n }\n this.logger.fatal({ err })\n process.exit(1)\n }\n\n configureLogger() {\n this.logger = new Logger(this.config).logger.child({\n source: 'app',\n })\n }\n\n async configureRedis() {\n const redisOptions = {\n db: this.redisConfig.db,\n shouldReconnect: this.redisConfig.shouldReconnect,\n password: this.redisConfig.password,\n }\n if (!redisOptions.password) delete redisOptions.password\n try {\n this.redisClient = await redisConnect(\n this.redisConfig.url,\n redisOptions,\n this.logger\n )\n } catch (err) {\n this.exit(err)\n }\n }\n\n async configurePostgreSQL() {\n try {\n this.db = await pgConnect(\n this.pgConfig.url,\n this.pgConfig.options,\n this.logger\n )\n } catch (err) {\n this.exit(err)\n }\n }\n\n async configureKafka() {\n try {\n this.logger.debug('Connecting API Kafka client...')\n const cfg = this.config.get('app.services.kafka.api.client')\n this.apiKafkaClient = await kafkaClientConnect(cfg.url, cfg.clientId, this.logger)\n\n this.logger.debug('Connecting API Kafka producer...')\n const producerCfg = this.config.get('app.services.kafka.api.producer')\n this.apiKafkaProducer = await kafkaProducerConnect(\n this.apiKafkaClient,\n producerCfg,\n this.logger\n )\n } catch (err) {\n this.exit(err)\n }\n }\n\n async initializeServices() {\n try {\n this.logger.debug('Starting redis configuration...')\n await this.configureRedis()\n this.logger.debug('Starting PostgreSQL configuration...')\n await this.configurePostgreSQL()\n this.logger.debug('Starting Kafka configuration...')\n await this.configureKafka()\n } catch (err) {\n this.exit(err)\n }\n }\n\n configureMiddleware() {\n this.koaApp.use(async (ctx, next) => {\n const start = new Date()\n await next()\n const ms = new Date() - start\n ctx.set('X-Response-Time', `${ms}ms`)\n })\n }\n\n async initializeApp() {\n await this.initializeServices()\n this.handlers.forEach((handler) => {\n this.allowedMethods.forEach((methodName) => {\n if (!handler[methodName]) {\n return\n }\n const handlerMethod = handler[methodName].bind(handler)\n const method = _[methodName]\n this.koaApp.use(\n method(handler.route, async (ctx) => {\n await handlerMethod(ctx)\n })\n )\n })\n })\n }\n\n async run() {\n const PORT = this.config.get('app.port')\n await this.initializeApp()\n\n this.logger.info(`Listening on port ${PORT}...`)\n this.koaApp.listen(PORT)\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/api/app.js","module.exports = require(\"path\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"path\"\n// module id = 8\n// module chunks = 0","module.exports = require(\"koa\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"koa\"\n// module id = 9\n// module chunks = 0","module.exports = require(\"koa-route\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"koa-route\"\n// module id = 10\n// module chunks = 0","import bunyan from 'bunyan'\nimport version from '../extensions/version'\n\nexport default class Logger {\n constructor(config) {\n this.config = config\n this.logLevel = config.get('app.log.level')\n this.logToStdOut = this.config.get('app.log.logToStdOut')\n this.logToFile = this.config.get('app.log.logToFile')\n this.logFile = this.config.get('app.log.file')\n this.configureLogger()\n }\n\n getStreams() {\n const streams = []\n if (this.logToStdOut) {\n streams.push({\n stream: process.stdout,\n level: this.logLevel,\n })\n }\n if (this.logToFile) {\n streams.push({\n path: this.logFile,\n level: this.logLevel,\n })\n }\n return streams\n }\n\n configureLogger() {\n this.logger = bunyan.createLogger({\n name: this.config.get('app.name'),\n src: false,\n streams: this.getStreams(),\n serializers: { err: bunyan.stdSerializers.err },\n }).child({ version }, true)\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/extensions/logger.js","module.exports = require(\"bunyan\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"bunyan\"\n// module id = 12\n// module chunks = 0","import pjson from '../../package.json'\n\nconst version = pjson.version\n\nexport default version\n\n\n\n// WEBPACK FOOTER //\n// ./src/extensions/version.js","module.exports = {\n\t\"name\": \"marathon\",\n\t\"version\": \"0.1.0\",\n\t\"description\": \"Marathon push processing system\",\n\t\"main\": \"src/index.js\",\n\t\"scripts\": {\n\t\t\"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n\t},\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"git@git.topfreegames.com:topfreegames/marathon.git\"\n\t},\n\t\"author\": \"TFG Co\",\n\t\"license\": \"ISC\",\n\t\"devDependencies\": {\n\t\t\"babel-cli\": \"^6.16.0\",\n\t\t\"babel-core\": \"^6.17.0\",\n\t\t\"babel-istanbul\": \"^0.11.0\",\n\t\t\"babel-loader\": \"^6.2.5\",\n\t\t\"babel-plugin-syntax-async-functions\": \"^6.13.0\",\n\t\t\"babel-plugin-transform-async-to-generator\": \"^6.16.0\",\n\t\t\"babel-plugin-transform-regenerator\": \"^6.16.1\",\n\t\t\"babel-plugin-transform-runtime\": \"^6.15.0\",\n\t\t\"babel-polyfill\": \"^6.16.0\",\n\t\t\"babel-preset-es2015\": \"^6.16.0\",\n\t\t\"babel-register\": \"^6.16.3\",\n\t\t\"chai\": \"^3.5.0\",\n\t\t\"chai-http\": \"^3.0.0\",\n\t\t\"coveralls\": \"^2.11.14\",\n\t\t\"dirty-chai\": \"^1.2.2\",\n\t\t\"eslint\": \"^3.9.1\",\n\t\t\"eslint-config-airbnb-base\": \"^8.0.0\",\n\t\t\"eslint-plugin-import\": \"^1.16.0\",\n\t\t\"flow-bin\": \"^0.34.0\",\n\t\t\"graceful-fs\": \"^4.1.10\",\n\t\t\"istanbul\": \"^0.4.5\",\n\t\t\"mocha\": \"^3.1.2\",\n\t\t\"mocha-lcov-reporter\": \"^1.2.0\",\n\t\t\"plato\": \"^1.7.0\",\n\t\t\"stylish\": \"^1.0.0\",\n\t\t\"stylus\": \"^0.54.5\",\n\t\t\"supertest\": \"^2.0.0\",\n\t\t\"supertest-as-promised\": \"^4.0.0\",\n\t\t\"uuid\": \"^2.0.3\",\n\t\t\"webpack\": \"^1.13.2\"\n\t},\n\t\"dependencies\": {\n\t\t\"babel-runtime\": \"^6.11.6\",\n\t\t\"bluebird\": \"^3.4.6\",\n\t\t\"bufferutil\": \"^1.2.1\",\n\t\t\"bunyan\": \"^1.8.1\",\n\t\t\"commander\": \"^2.9.0\",\n\t\t\"config\": \"^1.21.0\",\n\t\t\"js-yaml\": \"^3.6.1\",\n\t\t\"json-loader\": \"^0.5.4\",\n\t\t\"kafka-node\": \"^1.0.5\",\n\t\t\"koa\": \"^2.0.0-alpha.7\",\n\t\t\"koa-route\": \"^3.2.0\",\n\t\t\"mongoose\": \"^4.6.5\",\n\t\t\"pg\": \"^6.1.0\",\n\t\t\"pg-hstore\": \"^2.3.2\",\n\t\t\"pg-native\": \"^1.10.0\",\n\t\t\"redis\": \"^2.6.2\",\n\t\t\"redis-info\": \"^3.0.6\",\n\t\t\"redlock\": \"^2.0.1\",\n\t\t\"sequelize\": \"^3.24.7\",\n\t\t\"utf-8-validate\": \"^1.2.1\",\n\t\t\"validator\": \"^6.0.0\"\n\t},\n\t\"bin\": {\n\t\t\"marathon\": \"./lib/marathon.js\"\n\t}\n};\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./package.json\n// module id = 14\n// module chunks = 0","import { check as redisCheck } from '../../extensions/redis'\nimport { check as pgCheck } from '../../extensions/postgresql'\nimport { check as kafkaClientCheck } from '../../extensions/kafkaClient'\nimport { check as kafkaProducerCheck } from '../../extensions/kafkaProducer'\n\nexport default class HealthcheckHandler {\n constructor(app) {\n this.app = app\n this.route = '/healthcheck'\n this.resetServices()\n }\n\n resetServices() {\n this.services = {\n redis: { up: false },\n postgreSQL: { up: false },\n apiKafkaClient: { up: false },\n apiKafkaProducer: { up: false },\n }\n }\n\n hasFailed() {\n return (\n !this.services.redis.up ||\n !this.services.postgreSQL.up ||\n !this.services.apiKafkaClient.up ||\n !this.services.apiKafkaProducer.up\n )\n }\n\n async get(ctx) {\n this.services.redis = await redisCheck(this.app.redisClient)\n this.services.postgreSQL = await pgCheck(this.app.db)\n this.services.apiKafkaClient = await kafkaClientCheck(this.app.apiKafkaClient)\n this.services.apiKafkaProducer = await kafkaProducerCheck(this.app.apiKafkaProducer)\n ctx.body = JSON.stringify(this.services)\n\n if (this.hasFailed()) {\n ctx.status = 500\n }\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/api/handlers/healthcheck.js","import redis from 'redis'\nimport bluebird from 'bluebird'\nimport parser from 'redis-info'\nimport Redlock from 'redlock'\n\nbluebird.promisifyAll(redis.RedisClient.prototype)\nbluebird.promisifyAll(redis.Multi.prototype)\n\nlet Lock = null\nexport const LockKey = 'lock::matchmaking'\nexport const LockTTL = 100\n\nexport async function check(redisClient) {\n const result = {\n up: false,\n error: null,\n uptime: null,\n connectedClients: null,\n blockedClients: null,\n usedMemory: null,\n totalSystemMemory: null,\n maxMemory: null,\n rejectedConnections: 0,\n cpuUsage: 0,\n }\n\n try {\n const res = await redisClient.infoAsync()\n if (res) {\n const info = parser.parse(res)\n result.up = true\n result.uptime = info.uptime_in_seconds\n result.connectedClients = info.connected_clients\n result.blockedClients = info.blocked_clients\n result.usedMemory = info.used_memory_human\n result.totalSystemMemory = info.total_system_memory_human\n result.maxMemory = info.maxmemory_human\n result.rejectedConnections = info.rejected_connections\n result.cpuUsage = info.used_cpu_user\n } else {\n result.error = 'Could not get server status!'\n }\n } catch (error) {\n result.error = error.message\n }\n\n return result\n}\n\nexport async function connect(redisUrl, options, logger) {\n const logr = logger.child({\n redisUrl,\n options,\n source: 'redis-extension',\n })\n logr.debug({ redisUrl, options }, 'connecting to redis...')\n if (!options.shouldReconnect) {\n options.retry_strategy = () => undefined\n }\n const redisClient = redis.createClient(redisUrl, options)\n\n const hasConnected = new Promise((resolve, reject) => {\n if (redisClient.ready) {\n resolve(redisClient)\n return\n }\n\n redisClient.on('ready', () => {\n logr.debug('Connection to redis has been established successfully.')\n resolve(redisClient)\n })\n\n redisClient.on('error', (err) => {\n logr.error({ err }, 'Redis error connecting.')\n reject(err)\n })\n\n redisClient.on('end', () => {\n logr.error('Redis connection closed.')\n reject(new Error('Redis connection closed.'))\n })\n })\n\n await hasConnected\n\n const result = await redisClient.pingAsync()\n if (!result) {\n throw new Error('Failed to get server status from redis.')\n }\n logr.info({ redisUrl }, 'Successfully connected to redis.')\n return redisClient\n}\n\nexport async function withCriticalSection(redisClient, f) {\n if (!Lock) {\n const options = { retryCount: 50, retryDelay: 10 }\n Lock = new Redlock([redisClient], options)\n }\n const rlock = await Lock.lock(LockKey, LockTTL)\n const res = await f()\n await rlock.unlock()\n return res\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/extensions/redis.js","module.exports = require(\"redis\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"redis\"\n// module id = 17\n// module chunks = 0","module.exports = require(\"bluebird\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"bluebird\"\n// module id = 18\n// module chunks = 0","module.exports = require(\"redis-info\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"redis-info\"\n// module id = 19\n// module chunks = 0","module.exports = require(\"redlock\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"redlock\"\n// module id = 20\n// module chunks = 0","import Sequelize from 'sequelize'\nimport models from '../models/index'\n\nexport async function check(db) {\n const result = {\n up: false,\n }\n\n try {\n const query = \"select * from pg_stat_activity where state='active';\"\n const deadlockQuery = 'SELECT blocked_locks.pid AS blocked_pid, ' +\n 'blocked_locks.virtualtransaction as blocked_transaction_id, ' +\n 'blocked_activity.usename AS blocked_user, ' +\n 'blocking_locks.pid AS blocking_pid, ' +\n 'blocking_locks.virtualtransaction as blocking_transaction_id, ' +\n 'blocking_activity.usename AS blocking_user, ' +\n 'blocked_activity.query AS blocked_statement, ' +\n 'blocking_activity.query AS blocking_statement ' +\n 'FROM pg_catalog.pg_locks blocked_locks ' +\n 'JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid ' +\n 'JOIN pg_catalog.pg_locks blocking_locks ' +\n 'ON blocking_locks.locktype = blocked_locks.locktype ' +\n 'AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE ' +\n 'AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation ' +\n 'AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page ' +\n 'AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple ' +\n 'AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid ' +\n 'AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid ' +\n 'AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid ' +\n 'AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid ' +\n 'AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid ' +\n 'AND blocking_locks.pid != blocked_locks.pid ' +\n 'JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid ' +\n 'WHERE NOT blocked_locks.GRANTED; '\n const res = await db.client.query(query, { type: Sequelize.QueryTypes.SELECT })\n if (res) {\n result.activeOperations = res.length\n const deadlock = await db.client.query(deadlockQuery, { type: Sequelize.QueryTypes.SELECT })\n result.deadlock = deadlock.length === 0\n result.deadlockOperations = []\n deadlock.forEach((row) => {\n result.deadlockOperations.push({\n blocked: {\n pid: row.blocked_pid,\n txId: row.blocked_transaction_id,\n user: row.blocked_user,\n statement: row.blocked_statement,\n },\n blocking: {\n pid: row.blocking_pid,\n txId: row.blocking_transaction_id,\n user: row.blocking_user,\n statement: row.blocking_statement,\n },\n })\n })\n result.up = true\n } else {\n result.error = 'Could not get server status!'\n }\n } catch (error) {\n result.error = error.message\n }\n\n return result\n}\n\nexport async function connect(pgUrl, options, logger) {\n let opt = options\n if (!options) {\n opt = {}\n }\n\n const logr = logger.child({\n pgUrl,\n options,\n source: 'postgresql-extension',\n })\n opt.dialect = 'postgres'\n\n logr.debug({ pgUrl, opt }, 'Connecting to PostgreSQL...')\n\n try {\n const db = {}\n const client = new Sequelize(pgUrl, opt)\n const query = 'select 1;'\n const res = await client.query(query, { type: Sequelize.QueryTypes.SELECT })\n if (!res) {\n const err = new Error('Failed to connect to PostgreSQL.')\n logr.error({ pgUrl, err }, err.message)\n throw err\n }\n\n logr.debug('Loading models...')\n models.forEach((model) => {\n db[model.name] = model\n logr.debug({ model: model.name }, 'Model loaded successfully.')\n })\n\n logr.debug('All models loaded successfully.')\n\n logr.debug('Loading model associations...')\n Object.keys(db).forEach((modelName) => {\n if (db[modelName].associate) {\n logr.debug({ modelName }, 'Loading model associations...')\n db[modelName].associate(db)\n logr.debug({ modelName }, 'Model associations loaded successfully.')\n }\n })\n\n db.client = client\n logger.info({ pgUrl }, 'Successfully connected to PostgreSQL.')\n return db\n } catch (err) {\n logger.error({ pgUrl, err }, 'Failed to connect to PostgreSQL.')\n throw err\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/extensions/postgresql.js","module.exports = require(\"sequelize\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"sequelize\"\n// module id = 22\n// module chunks = 0","import App from './app'\n\nconst models = [\n App,\n]\nexport default models\n\n\n\n// WEBPACK FOOTER //\n// ./src/models/index.js","const Sequelize = require('sequelize')\n\nmodule.exports = sequelize => (\n sequelize.define('app', {\n key: {\n type: Sequelize.STRING,\n allowNull: false,\n validate: { len: [1, 255] },\n },\n bundleId: {\n type: Sequelize.STRING,\n allowNull: false,\n validate: { len: [1, 2000] },\n },\n createdBy: {\n type: Sequelize.STRING,\n allowNull: false,\n validate: { len: [1, 2000] },\n },\n }, {\n timestamps: true,\n underscored: true,\n indexes: [\n { fields: ['key'], unique: true },\n ],\n })\n)\n\n\n\n// WEBPACK FOOTER //\n// ./src/models/app.js","import { Client } from 'kafka-node'\n\nexport async function check(kafkaClient) {\n const result = {\n up: kafkaClient.ready,\n error: null,\n }\n\n return result\n}\n\nexport async function connect(url, clientId, logger) {\n const logr = logger.child({\n url,\n clientId,\n source: 'kafka-client-extension',\n })\n logr.debug('Connecting to Kafka...')\n const kafkaClient = new Client(url, clientId)\n const hasConnected = new Promise((resolve, reject) => {\n kafkaClient.on('ready', () => {\n logr.debug('Kafka is ready.')\n resolve(kafkaClient)\n })\n kafkaClient.on('error', (err) => {\n logr.error({ err }, 'Failed to connect to kafka.')\n reject(err)\n })\n })\n\n logr.debug('Waiting for connection...')\n await hasConnected\n\n logr.info('Successfully connected to kafka.')\n return kafkaClient\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/extensions/kafkaClient.js","module.exports = require(\"kafka-node\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"kafka-node\"\n// module id = 26\n// module chunks = 0","import kafka from 'kafka-node'\n\nexport async function check(producer) {\n const result = {\n up: false,\n error: null,\n }\n\n try {\n result.up = producer.ready\n } catch (error) {\n result.error = error.message\n }\n\n return result\n}\n\nexport async function connect(client, options, logger) {\n const logr = logger.child({\n source: 'kafka-producer-extension',\n options,\n })\n logr.debug('Connecting to kafka producer...')\n const producer = new kafka.Producer(client, options)\n\n const hasConnected = new Promise((resolve, reject) => {\n if (producer.ready) {\n logr.debug('Connection to Kafka producer has been established successfully.')\n resolve(producer)\n return\n }\n\n producer.on('ready', () => {\n logr.debug('Connection to Kafka producer has been established successfully.')\n resolve(producer)\n })\n producer.on('error', (err) => {\n logr.error({ err }, 'Connection to Kafka producer failed.')\n reject(err)\n })\n })\n\n await hasConnected\n\n logr.info('Successfully connected to Kafka producer.')\n return producer\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/extensions/kafkaProducer.js"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack:///webpack/bootstrap 22707473342d92570c95","webpack:///external \"babel-polyfill\"","webpack:///./src/index.js","webpack:///(webpack)/buildin/module.js","webpack:///external \"commander\"","webpack:///./src/cmd/start.js","webpack:///external \"config\"","webpack:///./src/api/app.js","webpack:///external \"humps\"","webpack:///external \"path\"","webpack:///external \"koa-validate\"","webpack:///external \"koa\"","webpack:///external \"koa-route\"","webpack:///./src/extensions/logger.js","webpack:///external \"bunyan\"","webpack:///./src/extensions/version.js","webpack:///./package.json","webpack:///./src/api/handlers/healthcheck.js","webpack:///./src/extensions/redis.js","webpack:///external \"redis\"","webpack:///external \"bluebird\"","webpack:///external \"redis-info\"","webpack:///external \"redlock\"","webpack:///./src/extensions/postgresql.js","webpack:///external \"sequelize\"","webpack:///./src/models/index.js","webpack:///./src/models/app.js","webpack:///./src/extensions/kafkaClient.js","webpack:///external \"kafka-node\"","webpack:///./src/extensions/kafkaProducer.js","webpack:///./src/api/handlers/app.js","webpack:///external \"boom\""],"names":["RootCmd","rootCmd","version","args","parse","module","parent","cmd","run","process","argv","StartCmd","command","description","action","app","MarathonApp","config","allowedMethods","koaApp","configureLogger","configureMiddleware","handlersPath","join","__dirname","handlers","getHandlers","redisConfig","get","pgConfig","self","push","err","env","NODE_ENV","logger","fatal","exit","child","source","redisOptions","db","shouldReconnect","password","url","redisClient","options","debug","cfg","clientId","apiKafkaClient","producerCfg","apiKafkaProducer","configureRedis","configurePostgreSQL","configureKafka","use","ctx","next","start","Date","ms","set","initializeServices","forEach","handler","methodName","handlerMethod","bind","method","route","validate","apply","PORT","initializeApp","info","listen","Logger","logLevel","logToStdOut","logToFile","logFile","streams","stream","stdout","level","path","createLogger","name","src","getStreams","serializers","stdSerializers","HealthcheckHandler","resetServices","services","redis","up","postgreSQL","body","JSON","stringify","hasFailed","status","result","error","uptime","connectedClients","blockedClients","usedMemory","totalSystemMemory","maxMemory","rejectedConnections","cpuUsage","infoAsync","res","uptime_in_seconds","connected_clients","blocked_clients","used_memory_human","total_system_memory_human","maxmemory_human","rejected_connections","used_cpu_user","message","check","redisUrl","logr","retry_strategy","undefined","createClient","hasConnected","Promise","resolve","reject","ready","on","Error","pingAsync","connect","f","Lock","retryCount","retryDelay","lock","LockKey","LockTTL","rlock","unlock","withCriticalSection","promisifyAll","RedisClient","prototype","Multi","query","deadlockQuery","client","type","QueryTypes","SELECT","activeOperations","length","deadlock","deadlockOperations","row","blocked","pid","blocked_pid","txId","blocked_transaction_id","user","blocked_user","statement","blocked_statement","blocking","blocking_pid","blocking_transaction_id","blocking_user","blocking_statement","pgUrl","opt","dialect","Object","keys","model","modelName","associate","models","App","Sequelize","require","exports","sequelize","define","key","STRING","allowNull","len","bundleId","createdBy","timestamps","underscored","indexes","fields","unique","kafkaClient","producer","Producer","Boom","AppsHandler","checkHeaders","notEmpty","isEmail","checkQuery","match","errors","badData","output","payload","data","findAll","apps","request","header","create","AppHandler","findById","params","id","updateAttributes","updatedApp","destroy"],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAe;AACf;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;;;;;;;;;;;;;;ACtCA,4C;;;;;;;;;;;;;;ACAA;;;;AACA;;;;AACA;;;;;;KAEqBA,O;AACnB,sBAAc;AAAA;;AACZ,UAAKC,OAAL,GAAe,oBACZC,OADY,kBAAf;AAED;;;;yBAEGC,I,EAAM;AACR,YAAKF,OAAL,CAAaG,KAAb,CAAmBD,IAAnB;AACD;;;;;;mBARkBH,O;;;AAWrB,KAAI,CAACK,OAAOC,MAAZ,EAAoB;AAClB,OAAMC,MAAM,IAAIP,OAAJ,EAAZ;AACA,uBAAaO,IAAIN,OAAjB,EAFkB,CAEQ;AAC1BM,OAAIC,GAAJ,CAAQC,QAAQC,IAAhB;AACD,E;;;;;;;ACnBD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;ACTA,uC;;;;;;;;;;;;ACAA;;;;AACA;;;;;;;;KAEqBC,Q,GACnB,kBAAYV,OAAZ,EAAqB;AAAA;;AACnBA,WACGW,OADH,CACW,OADX,EAEGC,WAFH,CAEe,WAFf,EAGGC,MAHH,CAGU,YAAM;AACZ,SAAMC,MAAM,mCAAZ;AACAA,SAAIP,GAAJ;AACD,IANH;AAOD,E;;mBATkBG,Q;;;;;;ACHrB,oC;;;;;;;;;;;;;;ACAA;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;;;AACA;;AACA;;AACA;;AACA;;AACA;;;;;;;;KAGqBK,W;AACnB,wBAAYC,MAAZ,EAAoB;AAAA;;AAClB,UAAKA,MAAL,GAAcA,MAAd;AACA,UAAKC,cAAL,GAAsB,CAAC,KAAD,EAAQ,MAAR,EAAgB,KAAhB,EAAuB,QAAvB,CAAtB;AACA,UAAKC,MAAL,GAAc,mBAAd;AACA,UAAKC,eAAL;AACA,UAAKC,mBAAL;;AAEA,UAAKC,YAAL,GAAoB,eAAKC,IAAL,CAAUC,SAAV,EAAqB,iBAArB,CAApB;AACA,UAAKC,QAAL,GAAgB,KAAKC,WAAL,EAAhB;AACA,UAAKC,WAAL,GAAmBV,OAAOW,GAAP,CAAW,oBAAX,CAAnB;AACA,UAAKC,QAAL,GAAgBZ,OAAOW,GAAP,CAAW,yBAAX,CAAhB;AACD;;;;mCAEa;AACZ,WAAME,OAAO,IAAb;AACA,WAAML,WAAW,EAAjB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACAA,gBAASM,IAAT,CAAc,0BAAuBD,IAAvB,CAAd;AACAL,gBAASM,IAAT,CAAc,qBAAgBD,IAAhB,CAAd;AACAL,gBAASM,IAAT,CAAc,oBAAeD,IAAf,CAAd;;AAEA,cAAOL,QAAP;AACD;;;0BAEIO,G,EAAK;AACR,WAAIvB,QAAQwB,GAAR,CAAYC,QAAZ,KAAyB,MAA7B,EAAqC;AACnC,eAAMF,GAAN;AACD;AACD,YAAKG,MAAL,CAAYC,KAAZ,CAAkB,EAAEJ,QAAF,EAAlB;AACAvB,eAAQ4B,IAAR,CAAa,CAAb;AACD;;;uCAEiB;AAChB,YAAKF,MAAL,GAAc,qBAAW,KAAKlB,MAAhB,EAAwBkB,MAAxB,CAA+BG,KAA/B,CAAqC;AACjDC,iBAAQ;AADyC,QAArC,CAAd;AAGD;;;;;;;;;;AAGOC,6B,GAAe;AACnBC,uBAAI,KAAKd,WAAL,CAAiBc,EADF;AAEnBC,oCAAiB,KAAKf,WAAL,CAAiBe,eAFf;AAGnBC,6BAAU,KAAKhB,WAAL,CAAiBgB;AAHR,kB;;AAKrB,qBAAI,CAACH,aAAaG,QAAlB,EAA4B,OAAOH,aAAaG,QAApB;;;wBAED,oBACvB,KAAKhB,WAAL,CAAiBiB,GADM,EAEvBJ,YAFuB,EAGvB,KAAKL,MAHkB,C;;;AAAzB,sBAAKU,W;;;;;;;;AAML,sBAAKR,IAAL;;;;;;;;;;;;;;;;;;;;;;;;;;wBAMgB,yBACd,KAAKR,QAAL,CAAce,GADA,EAEd,KAAKf,QAAL,CAAciB,OAFA,EAGd,KAAKX,MAHS,C;;;AAAhB,sBAAKM,E;;;;;;;;AAML,sBAAKJ,IAAL;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,sBAAKF,MAAL,CAAYY,KAAZ,CAAkB,gCAAlB;AACMC,oB,GAAM,KAAK/B,MAAL,CAAYW,GAAZ,CAAgB,+BAAhB,C;;wBACgB,0BAAmBoB,IAAIJ,GAAvB,EAA4BI,IAAIC,QAAhC,EAA0C,KAAKd,MAA/C,C;;;AAA5B,sBAAKe,c;;;AAEL,sBAAKf,MAAL,CAAYY,KAAZ,CAAkB,kCAAlB;AACMI,4B,GAAc,KAAKlC,MAAL,CAAYW,GAAZ,CAAgB,iCAAhB,C;;wBACU,4BAC5B,KAAKsB,cADuB,EAE5BC,WAF4B,EAG5B,KAAKhB,MAHuB,C;;;AAA9B,sBAAKiB,gB;;;;;;;;AAML,sBAAKf,IAAL;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,sBAAKF,MAAL,CAAYY,KAAZ,CAAkB,iCAAlB;;wBACM,KAAKM,cAAL,E;;;AACN,sBAAKlB,MAAL,CAAYY,KAAZ,CAAkB,sCAAlB;;wBACM,KAAKO,mBAAL,E;;;AACN,sBAAKnB,MAAL,CAAYY,KAAZ,CAAkB,iCAAlB;;wBACM,KAAKQ,cAAL,E;;;;;;;;;;AAEN,sBAAKlB,IAAL;;;;;;;;;;;;;;;;;;2CAIkB;AAAA;;AACpB,YAAKlB,MAAL,CAAYqC,GAAZ;AAAA,+DAAgB,kBAAOC,GAAP,EAAYC,IAAZ;AAAA;AAAA;AAAA;AAAA;AAAA;AACRC,wBADQ,GACA,IAAIC,IAAJ,EADA;AAAA;AAAA,0BAERF,MAFQ;;AAAA;AAGRG,qBAHQ,GAGH,IAAID,IAAJ,KAAaD,KAHV;;AAIdF,uBAAIK,GAAJ,CAAQ,iBAAR,EAA8BD,EAA9B;;AAJc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAAhB;;AAAA;AAAA;AAAA;AAAA;AAMA,kCAAY,KAAK1C,MAAjB;AACD;;;;;;;;;;;;wBAGO,KAAK4C,kBAAL,E;;;AACN,sBAAKtC,QAAL,CAAcuC,OAAd,CAAsB,UAACC,OAAD,EAAa;AACjC,0BAAK/C,cAAL,CAAoB8C,OAApB,CAA4B,UAACE,UAAD,EAAgB;AAC1C,yBAAI,CAACD,QAAQC,UAAR,CAAL,EAA0B;AACxB;AACD;AACD,yBAAMC,gBAAgBF,QAAQC,UAAR,EAAoBE,IAApB,CAAyBH,OAAzB,CAAtB;AACA,yBAAMI,SAAS,mBAAEH,UAAF,CAAf;AACA,yBAAM/D,OAAO,CAAC8D,QAAQK,KAAT,CAAb;AACA,yBAAMC,WAAWN,QAAQ,mCAAqBC,UAArB,CAAR,CAAjB;AACA,yBAAIK,QAAJ,EAAc;AACZpE,4BAAK4B,IAAL,CAAUwC,QAAV;AACD;AACDpE,0BAAK4B,IAAL;AAAA,6EAAU,kBAAO0B,GAAP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wCACFU,cAAcV,GAAd,CADE;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAV;;AAAA;AAAA;AAAA;AAAA;;AAIA,4BAAKtC,MAAL,CAAYqC,GAAZ,CAAgBa,OAAOG,KAAP,CAAaP,OAAb,EAAsB9D,IAAtB,CAAhB;AACD,oBAhBD;AAiBD,kBAlBD;;;;;;;;;;;;;;;;;;;;;;;;;AAsBMsE,qB,GAAO,KAAKxD,MAAL,CAAYW,GAAZ,CAAgB,UAAhB,C;;wBACP,KAAK8C,aAAL,E;;;;AAEN,sBAAKvC,MAAL,CAAYwC,IAAZ,wBAAsCF,IAAtC;AACA,sBAAKtD,MAAL,CAAYyD,MAAZ,CAAmBH,IAAnB;;;;;;;;;;;;;;;;;;;;;mBAjJiBzD,W;;;;;;;ACdrB,mC;;;;;;ACAA,kC;;;;;;ACAA,0C;;;;;;ACAA,iC;;;;;;ACAA,uC;;;;;;;;;;;;;;ACAA;;;;AACA;;;;;;;;KAEqB6D,M;AACnB,mBAAY5D,MAAZ,EAAoB;AAAA;;AAClB,UAAKA,MAAL,GAAcA,MAAd;AACA,UAAK6D,QAAL,GAAgB7D,OAAOW,GAAP,CAAW,eAAX,CAAhB;AACA,UAAKmD,WAAL,GAAmB,KAAK9D,MAAL,CAAYW,GAAZ,CAAgB,qBAAhB,CAAnB;AACA,UAAKoD,SAAL,GAAiB,KAAK/D,MAAL,CAAYW,GAAZ,CAAgB,mBAAhB,CAAjB;AACA,UAAKqD,OAAL,GAAe,KAAKhE,MAAL,CAAYW,GAAZ,CAAgB,cAAhB,CAAf;AACA,UAAKR,eAAL;AACD;;;;kCAEY;AACX,WAAM8D,UAAU,EAAhB;AACA,WAAI,KAAKH,WAAT,EAAsB;AACpBG,iBAAQnD,IAAR,CAAa;AACXoD,mBAAQ1E,QAAQ2E,MADL;AAEXC,kBAAO,KAAKP;AAFD,UAAb;AAID;AACD,WAAI,KAAKE,SAAT,EAAoB;AAClBE,iBAAQnD,IAAR,CAAa;AACXuD,iBAAM,KAAKL,OADA;AAEXI,kBAAO,KAAKP;AAFD,UAAb;AAID;AACD,cAAOI,OAAP;AACD;;;uCAEiB;AAChB,YAAK/C,MAAL,GAAc,iBAAOoD,YAAP,CAAoB;AAChCC,eAAM,KAAKvE,MAAL,CAAYW,GAAZ,CAAgB,UAAhB,CAD0B;AAEhC6D,cAAK,KAF2B;AAGhCP,kBAAS,KAAKQ,UAAL,EAHuB;AAIhCC,sBAAa,EAAE3D,KAAK,iBAAO4D,cAAP,CAAsB5D,GAA7B;AAJmB,QAApB,EAKXM,KALW,CAKL,EAAEpC,0BAAF,EALK,EAKQ,IALR,CAAd;AAMD;;;;;;mBAlCkB2E,M;;;;;;ACHrB,oC;;;;;;;;;;;;ACAA;;;;;;AAEA,KAAM3E,UAAU,kBAAMA,OAAtB;;mBAEeA,O;;;;;;ACJf;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAE;AACF;AACA;AACA;AACA,GAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAE;AACF;AACA;AACA;AACA,G;;;;;;;;;;;;;;AC3EA;;AACA;;AACA;;AACA;;;;;;KAEqB2F,kB;AACnB,+BAAY9E,GAAZ,EAAiB;AAAA;;AACf,UAAKA,GAAL,GAAWA,GAAX;AACA,UAAKuD,KAAL,GAAa,cAAb;AACA,UAAKwB,aAAL;AACD;;;;qCAEe;AACd,YAAKC,QAAL,GAAgB;AACdC,gBAAO,EAAEC,IAAI,KAAN,EADO;AAEdC,qBAAY,EAAED,IAAI,KAAN,EAFE;AAGd/C,yBAAgB,EAAE+C,IAAI,KAAN,EAHF;AAId7C,2BAAkB,EAAE6C,IAAI,KAAN;AAJJ,QAAhB;AAMD;;;iCAEW;AACV,cACE,CAAC,KAAKF,QAAL,CAAcC,KAAd,CAAoBC,EAArB,IACA,CAAC,KAAKF,QAAL,CAAcG,UAAd,CAAyBD,EAD1B,IAEA,CAAC,KAAKF,QAAL,CAAc7C,cAAd,CAA6B+C,EAF9B,IAGA,CAAC,KAAKF,QAAL,CAAc3C,gBAAd,CAA+B6C,EAJlC;AAMD;;;;6EAESxC,G;;;;;;wBACoB,kBAAW,KAAK1C,GAAL,CAAS8B,WAApB,C;;;AAA5B,sBAAKkD,QAAL,CAAcC,K;;wBACmB,uBAAQ,KAAKjF,GAAL,CAAS0B,EAAjB,C;;;AAAjC,sBAAKsD,QAAL,CAAcG,U;;wBACuB,wBAAiB,KAAKnF,GAAL,CAASmC,cAA1B,C;;;AAArC,sBAAK6C,QAAL,CAAc7C,c;;wBACyB,0BAAmB,KAAKnC,GAAL,CAASqC,gBAA5B,C;;;AAAvC,sBAAK2C,QAAL,CAAc3C,gB;;AACdK,qBAAI0C,IAAJ,GAAWC,KAAKC,SAAL,CAAe,KAAKN,QAApB,CAAX;;AAEA,qBAAI,KAAKO,SAAL,EAAJ,EAAsB;AACpB7C,uBAAI8C,MAAJ,GAAa,GAAb;AACD;;;;;;;;;;;;;;;;;;;;;mBAlCgBV,kB;;;;;;;;;;;;;;wDCOd,iBAAqBhD,WAArB;AAAA;AAAA;AAAA;AAAA;AAAA;AACC2D,mBADD,GACU;AACbP,mBAAI,KADS;AAEbQ,sBAAO,IAFM;AAGbC,uBAAQ,IAHK;AAIbC,iCAAkB,IAJL;AAKbC,+BAAgB,IALH;AAMbC,2BAAY,IANC;AAObC,kCAAmB,IAPN;AAQbC,0BAAW,IARE;AASbC,oCAAqB,CATR;AAUbC,yBAAU;AAVG,cADV;AAAA;AAAA;AAAA,oBAeepE,YAAYqE,SAAZ,EAff;;AAAA;AAeGC,gBAfH;;AAgBH,iBAAIA,GAAJ,EAAS;AACDxC,mBADC,GACM,oBAAOvE,KAAP,CAAa+G,GAAb,CADN;;AAEPX,sBAAOP,EAAP,GAAY,IAAZ;AACAO,sBAAOE,MAAP,GAAgB/B,KAAKyC,iBAArB;AACAZ,sBAAOG,gBAAP,GAA0BhC,KAAK0C,iBAA/B;AACAb,sBAAOI,cAAP,GAAwBjC,KAAK2C,eAA7B;AACAd,sBAAOK,UAAP,GAAoBlC,KAAK4C,iBAAzB;AACAf,sBAAOM,iBAAP,GAA2BnC,KAAK6C,yBAAhC;AACAhB,sBAAOO,SAAP,GAAmBpC,KAAK8C,eAAxB;AACAjB,sBAAOQ,mBAAP,GAA6BrC,KAAK+C,oBAAlC;AACAlB,sBAAOS,QAAP,GAAkBtC,KAAKgD,aAAvB;AACD,cAXD,MAWO;AACLnB,sBAAOC,KAAP,GAAe,8BAAf;AACD;AA7BE;AAAA;;AAAA;AAAA;AAAA;;AA+BHD,oBAAOC,KAAP,GAAe,YAAMmB,OAArB;;AA/BG;AAAA,8CAkCEpB,MAlCF;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,I;;mBAAeqB,K;;;;;;yDAqCf,kBAAuBC,QAAvB,EAAiChF,OAAjC,EAA0CX,MAA1C;AAAA;AAAA;AAAA;AAAA;AAAA;AACC4F,iBADD,GACQ5F,OAAOG,KAAP,CAAa;AACxBwF,iCADwB;AAExBhF,+BAFwB;AAGxBP,uBAAQ;AAHgB,cAAb,CADR;;AAMLwF,kBAAKhF,KAAL,CAAW,EAAE+E,kBAAF,EAAYhF,gBAAZ,EAAX,EAAkC,wBAAlC;AACA,iBAAI,CAACA,QAAQJ,eAAb,EAA8B;AAC5BI,uBAAQkF,cAAR,GAAyB;AAAA,wBAAMC,SAAN;AAAA,gBAAzB;AACD;AACKpF,wBAVD,GAUe,gBAAMqF,YAAN,CAAmBJ,QAAnB,EAA6BhF,OAA7B,CAVf;AAYCqF,yBAZD,GAYgB,IAAIC,OAAJ,CAAY,UAACC,OAAD,EAAUC,MAAV,EAAqB;AACpD,mBAAIzF,YAAY0F,KAAhB,EAAuB;AACrBF,yBAAQxF,WAAR;AACA;AACD;;AAEDA,2BAAY2F,EAAZ,CAAe,OAAf,EAAwB,YAAM;AAC5BT,sBAAKhF,KAAL,CAAW,wDAAX;AACAsF,yBAAQxF,WAAR;AACD,gBAHD;;AAKAA,2BAAY2F,EAAZ,CAAe,OAAf,EAAwB,UAACxG,GAAD,EAAS;AAC/B+F,sBAAKtB,KAAL,CAAW,EAAEzE,QAAF,EAAX,EAAoB,yBAApB;AACAsG,wBAAOtG,GAAP;AACD,gBAHD;;AAKAa,2BAAY2F,EAAZ,CAAe,KAAf,EAAsB,YAAM;AAC1BT,sBAAKtB,KAAL,CAAW,0BAAX;AACA6B,wBAAO,IAAIG,KAAJ,CAAU,0BAAV,CAAP;AACD,gBAHD;AAID,cApBoB,CAZhB;AAAA;AAAA,oBAkCCN,YAlCD;;AAAA;AAAA;AAAA,oBAoCgBtF,YAAY6F,SAAZ,EApChB;;AAAA;AAoCClC,mBApCD;;AAAA,iBAqCAA,MArCA;AAAA;AAAA;AAAA;;AAAA,mBAsCG,IAAIiC,KAAJ,CAAU,yCAAV,CAtCH;;AAAA;AAwCLV,kBAAKpD,IAAL,CAAU,EAAEmD,kBAAF,EAAV,EAAwB,kCAAxB;AAxCK,+CAyCEjF,WAzCF;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,I;;mBAAe8F,O;;;;;;yDA4Cf,kBAAmC9F,WAAnC,EAAgD+F,CAAhD;AAAA;AAAA;AAAA;AAAA;AAAA;AACL,iBAAI,CAACC,IAAL,EAAW;AACH/F,sBADG,GACO,EAAEgG,YAAY,EAAd,EAAkBC,YAAY,EAA9B,EADP;;AAETF,sBAAO,sBAAY,CAAChG,WAAD,CAAZ,EAA2BC,OAA3B,CAAP;AACD;AAJI;AAAA,oBAKe+F,KAAKG,IAAL,CAAUC,OAAV,EAAmBC,OAAnB,CALf;;AAAA;AAKCC,kBALD;AAAA;AAAA,oBAMaP,GANb;;AAAA;AAMCzB,gBAND;AAAA;AAAA,oBAOCgC,MAAMC,MAAN,EAPD;;AAAA;AAAA,+CAQEjC,GARF;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,I;;mBAAekC,mB;;;;;AA7FtB;;;;AACA;;;;AACA;;;;AACA;;;;;;;;AAEA,oBAASC,YAAT,CAAsB,gBAAMC,WAAN,CAAkBC,SAAxC;AACA,oBAASF,YAAT,CAAsB,gBAAMG,KAAN,CAAYD,SAAlC;;AAEA,KAAIX,OAAO,IAAX;AACO,KAAMI,4BAAU,mBAAhB;AACA,KAAMC,4BAAU,GAAhB,C;;;;;;ACVP,mC;;;;;;ACAA,sC;;;;;;ACAA,wC;;;;;;ACAA,qC;;;;;;;;;;;;;;;;wDCGO,iBAAqBzG,EAArB;AAAA;AAAA;AAAA;AAAA;AAAA;AACC+D,mBADD,GACU;AACbP,mBAAI;AADS,cADV;AAAA;AAMGyD,kBANH,GAMW,sDANX;AAOGC,0BAPH,GAOmB,kDACf,8DADe,GAEf,6CAFe,GAGf,0CAHe,GAIf,gEAJe,GAKf,8CALe,GAMf,kDANe,GAOf,kDAPe,GAQlB,kDARkB,GASlB,iGATkB,GAUlB,mDAVkB,GAWd,sDAXc,GAYd,0EAZc,GAad,0EAbc,GAcd,kEAdc,GAed,oEAfc,GAgBd,8EAhBc,GAiBd,oFAjBc,GAkBd,wEAlBc,GAmBd,oEAnBc,GAoBd,0EApBc,GAqBd,8CArBc,GAsBlB,mGAtBkB,GAuBlB,mCA9BD;AAAA;AAAA,oBA+BelH,GAAGmH,MAAH,CAAUF,KAAV,CAAgBA,KAAhB,EAAuB,EAAEG,MAAM,oBAAUC,UAAV,CAAqBC,MAA7B,EAAvB,CA/Bf;;AAAA;AA+BG5C,gBA/BH;;AAAA,kBAgCCA,GAhCD;AAAA;AAAA;AAAA;;AAiCDX,oBAAOwD,gBAAP,GAA0B7C,IAAI8C,MAA9B;AAjCC;AAAA,oBAkCsBxH,GAAGmH,MAAH,CAAUF,KAAV,CAAgBC,aAAhB,EAA+B,EAAEE,MAAM,oBAAUC,UAAV,CAAqBC,MAA7B,EAA/B,CAlCtB;;AAAA;AAkCKG,qBAlCL;;AAmCD1D,oBAAO0D,QAAP,GAAkBA,SAASD,MAAT,KAAoB,CAAtC;AACAzD,oBAAO2D,kBAAP,GAA4B,EAA5B;AACAD,sBAASlG,OAAT,CAAiB,UAACoG,GAAD,EAAS;AACxB5D,sBAAO2D,kBAAP,CAA0BpI,IAA1B,CAA+B;AAC7BsI,0BAAS;AACPC,wBAAKF,IAAIG,WADF;AAEPC,yBAAMJ,IAAIK,sBAFH;AAGPC,yBAAMN,IAAIO,YAHH;AAIPC,8BAAWR,IAAIS;AAJR,kBADoB;AAO7BC,2BAAU;AACRR,wBAAKF,IAAIW,YADD;AAERP,yBAAMJ,IAAIY,uBAFF;AAGRN,yBAAMN,IAAIa,aAHF;AAIRL,8BAAWR,IAAIc;AAJP;AAPmB,gBAA/B;AAcD,cAfD;AAgBA1E,oBAAOP,EAAP,GAAY,IAAZ;AArDC;AAAA;;AAAA;AAuDDO,oBAAOC,KAAP,GAAe,8BAAf;;AAvDC;AAAA;AAAA;;AAAA;AAAA;AAAA;;AA0DHD,oBAAOC,KAAP,GAAe,YAAMmB,OAArB;;AA1DG;AAAA,8CA6DEpB,MA7DF;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,I;;mBAAeqB,K;;;;;;yDAgEf,kBAAuBsD,KAAvB,EAA8BrI,OAA9B,EAAuCX,MAAvC;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AACDiJ,gBADC,GACKtI,OADL;;AAEL,iBAAI,CAACA,OAAL,EAAc;AACZsI,qBAAM,EAAN;AACD;;AAEKrD,iBAND,GAMQ5F,OAAOG,KAAP,CAAa;AACxB6I,2BADwB;AAExBrI,+BAFwB;AAGxBP,uBAAQ;AAHgB,cAAb,CANR;;AAWL6I,iBAAIC,OAAJ,GAAc,UAAd;;AAEAtD,kBAAKhF,KAAL,CAAW,EAAEoI,YAAF,EAASC,QAAT,EAAX,EAA2B,6BAA3B;;AAbK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBG3I,yBAhBH,GAgBQ,EAhBR;AAiBGmH,6BAjBH,GAiBY,wBAAcuB,KAAd,EAAqBC,GAArB,CAjBZ;AAkBG1B,4BAlBH,GAkBW,WAlBX;AAAA;AAAA,8BAmBeE,OAAOF,KAAP,CAAaA,KAAb,EAAoB,EAAEG,MAAM,oBAAUC,UAAV,CAAqBC,MAA7B,EAApB,CAnBf;;AAAA;AAmBG5C,0BAnBH;;AAAA,2BAoBEA,GApBF;AAAA;AAAA;AAAA;;AAqBKnF,0BArBL,GAqBW,IAAIyG,KAAJ,CAAU,kCAAV,CArBX;;AAsBDV,4BAAKtB,KAAL,CAAW,EAAE0E,YAAF,EAASnJ,QAAT,EAAX,EAA2BA,IAAI4F,OAA/B;AAtBC,6BAuBK5F,GAvBL;;AAAA;;AA0BH+F,4BAAKhF,KAAL,CAAW,mBAAX;AACAuI,8BAAOC,IAAP,kBAAoBvH,OAApB,CAA4B,UAACwH,KAAD,EAAW;AACrC/I,4BAAG+I,KAAH,IAAY,gBAAOA,KAAP,CAAZ;AACAzD,8BAAKhF,KAAL,CAAW,EAAEyI,YAAF,EAAX,EAAsB,4BAAtB;AACD,wBAHD;;AAKAzD,4BAAKhF,KAAL,CAAW,iCAAX;;AAEAgF,4BAAKhF,KAAL,CAAW,+BAAX;AACAuI,8BAAOC,IAAP,CAAY9I,EAAZ,EAAgBuB,OAAhB,CAAwB,UAACyH,SAAD,EAAe;AACrC,6BAAIhJ,GAAGgJ,SAAH,EAAcC,SAAlB,EAA6B;AAC3B3D,gCAAKhF,KAAL,CAAW,EAAE0I,oBAAF,EAAX,EAA0B,+BAA1B;AACAhJ,8BAAGgJ,SAAH,EAAcC,SAAd,CAAwBjJ,EAAxB;AACAsF,gCAAKhF,KAAL,CAAW,EAAE0I,oBAAF,EAAX,EAA0B,yCAA1B;AACD;AACF,wBAND;;AAQAhJ,0BAAGmH,MAAH,GAAYA,MAAZ;AACAzH,8BAAOwC,IAAP,CAAY,EAAEwG,YAAF,EAAZ,EAAuB,uCAAvB;AA5CG;AAAA,4BA6CI1I;AA7CJ;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AA+CHN,oBAAOsE,KAAP,CAAa,EAAE0E,YAAF,EAASnJ,iBAAT,EAAb,EAA6B,kCAA7B;AA/CG;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,I;;mBAAe2G,O;;;;;AAnEtB;;;;AACA;;;;;;;;;;;;ACDA,uC;;;;;;;;;;;;ACAA;;;;;;AAEA,KAAMgD,SAAS;AACbC;AADa,EAAf;mBAGeD,M;;;;;;;;ACLf,KAAME,YAAY,mBAAAC,CAAQ,EAAR,CAAlB;;AAEAzL,QAAO0L,OAAP,GAAiB;AAAA,UACfC,UAAUC,MAAV,CAAiB,KAAjB,EAAwB;AACtBC,UAAK;AACHrC,aAAMgC,UAAUM,MADb;AAEHC,kBAAW,KAFR;AAGH7H,iBAAU,EAAE8H,KAAK,CAAC,CAAD,EAAI,GAAJ,CAAP;AAHP,MADiB;AAMtBC,eAAU;AACRzC,aAAMgC,UAAUM,MADR;AAERC,kBAAW,KAFH;AAGR7H,iBAAU,EAAE8H,KAAK,CAAC,CAAD,EAAI,IAAJ,CAAP;AAHF,MANY;AAWtBE,gBAAW;AACT1C,aAAMgC,UAAUM,MADP;AAETC,kBAAW,KAFF;AAGT7H,iBAAU,EAAE8H,KAAK,CAAC,CAAD,EAAI,IAAJ,CAAP;AAHD;AAXW,IAAxB,EAgBG;AACDG,iBAAY,IADX;AAEDC,kBAAa,IAFZ;AAGDC,cAAS,CACP,EAAEC,QAAQ,CAAC,KAAD,CAAV,EAAmBC,QAAQ,IAA3B,EADO;AAHR,IAhBH,CADe;AAAA,EAAjB,C;;;;;;;;;;;;;;wDCAO,iBAAqBC,WAArB;AAAA;AAAA;AAAA;AAAA;AAAA;AACCrG,mBADD,GACU;AACbP,mBAAI4G,YAAYtE,KADH;AAEb9B,sBAAO;AAFM,cADV;AAAA,8CAMED,MANF;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,I;;mBAAeqB,K;;;;;;yDASf,kBAAuBjF,GAAvB,EAA4BK,QAA5B,EAAsCd,MAAtC;AAAA;AAAA;AAAA;AAAA;AAAA;AACC4F,iBADD,GACQ5F,OAAOG,KAAP,CAAa;AACxBM,uBADwB;AAExBK,iCAFwB;AAGxBV,uBAAQ;AAHgB,cAAb,CADR;;AAMLwF,kBAAKhF,KAAL,CAAW,wBAAX;AACM8J,wBAPD,GAOe,sBAAWjK,GAAX,EAAgBK,QAAhB,CAPf;AAQCkF,yBARD,GAQgB,IAAIC,OAAJ,CAAY,UAACC,OAAD,EAAUC,MAAV,EAAqB;AACpDuE,2BAAYrE,EAAZ,CAAe,OAAf,EAAwB,YAAM;AAC5BT,sBAAKhF,KAAL,CAAW,iBAAX;AACAsF,yBAAQwE,WAAR;AACD,gBAHD;AAIAA,2BAAYrE,EAAZ,CAAe,OAAf,EAAwB,UAACxG,GAAD,EAAS;AAC/B+F,sBAAKtB,KAAL,CAAW,EAAEzE,QAAF,EAAX,EAAoB,6BAApB;AACAsG,wBAAOtG,GAAP;AACD,gBAHD;AAID,cAToB,CARhB;;;AAmBL+F,kBAAKhF,KAAL,CAAW,2BAAX;AAnBK;AAAA,oBAoBCoF,YApBD;;AAAA;;AAsBLJ,kBAAKpD,IAAL,CAAU,kCAAV;AAtBK,+CAuBEkI,WAvBF;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,I;;mBAAelE,O;;;;;AAXtB;;;;;;;;ACAA,wC;;;;;;;;;;;;;;wDCEO,iBAAqBmE,QAArB;AAAA;AAAA;AAAA;AAAA;AAAA;AACCtG,mBADD,GACU;AACbP,mBAAI,KADS;AAEbQ,sBAAO;AAFM,cADV;;;AAML,iBAAI;AACFD,sBAAOP,EAAP,GAAY6G,SAASvE,KAArB;AACD,cAFD,CAEE,OAAO9B,KAAP,EAAc;AACdD,sBAAOC,KAAP,GAAeA,MAAMmB,OAArB;AACD;;AAVI,8CAYEpB,MAZF;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,I;;mBAAeqB,K;;;;;;yDAef,kBAAuB+B,MAAvB,EAA+B9G,OAA/B,EAAwCX,MAAxC;AAAA;AAAA;AAAA;AAAA;AAAA;AACC4F,iBADD,GACQ5F,OAAOG,KAAP,CAAa;AACxBC,uBAAQ,0BADgB;AAExBO;AAFwB,cAAb,CADR;;AAKLiF,kBAAKhF,KAAL,CAAW,iCAAX;AACM+J,qBAND,GAMY,IAAI,oBAAMC,QAAV,CAAmBnD,MAAnB,EAA2B9G,OAA3B,CANZ;AAQCqF,yBARD,GAQgB,IAAIC,OAAJ,CAAY,UAACC,OAAD,EAAUC,MAAV,EAAqB;AACpD,mBAAIwE,SAASvE,KAAb,EAAoB;AAClBR,sBAAKhF,KAAL,CAAW,iEAAX;AACAsF,yBAAQyE,QAAR;AACA;AACD;;AAEDA,wBAAStE,EAAT,CAAY,OAAZ,EAAqB,YAAM;AACzBT,sBAAKhF,KAAL,CAAW,iEAAX;AACAsF,yBAAQyE,QAAR;AACD,gBAHD;AAIAA,wBAAStE,EAAT,CAAY,OAAZ,EAAqB,UAACxG,GAAD,EAAS;AAC5B+F,sBAAKtB,KAAL,CAAW,EAAEzE,QAAF,EAAX,EAAoB,sCAApB;AACAsG,wBAAOtG,GAAP;AACD,gBAHD;AAID,cAfoB,CARhB;AAAA;AAAA,oBAyBCmG,YAzBD;;AAAA;;AA2BLJ,kBAAKpD,IAAL,CAAU,2CAAV;AA3BK,+CA4BEmI,QA5BF;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,I;;mBAAenE,O;;;;;AAjBtB;;;;;;;;;;;;;;;;;;;;;;;;ACAA,KAAMqE,OAAO,mBAAAlB,CAAQ,EAAR,CAAb;;KAEamB,W,WAAAA,W;AACX,wBAAYlM,GAAZ,EAAiB;AAAA;;AACf,UAAKA,GAAL,GAAWA,GAAX;AACA,UAAKuD,KAAL,GAAa,OAAb;AACD;;;;;6EAEkBb,G,EAAKC,I;;;;;;AACtB,sBAAKwJ,YAAL,CAAkB,YAAlB,EAAgCC,QAAhC,GAA2CC,OAA3C;AACA,sBAAKC,UAAL,CAAgB,UAAhB,EAA4BF,QAA5B,GAAuCG,KAAvC,CAA6C,uCAA7C;AACA,sBAAKD,UAAL,CAAgB,KAAhB,EAAuBF,QAAvB,GAAkCd,GAAlC,CAAsC,CAAtC,EAAyC,GAAzC;;sBACI,KAAKkB,M;;;;;AACD9G,sB,GAAQuG,KAAKQ,OAAL,CAAa,iBAAb,EAAgC,KAAKD,MAArC,C;;AACd9J,qBAAI8C,MAAJ,GAAa,GAAb;AACA9C,qBAAI0C,IAAJ,GAAWM,MAAMgH,MAAN,CAAaC,OAAxB;AACAjK,qBAAI0C,IAAJ,CAASwH,IAAT,GAAgBlH,MAAMkH,IAAtB;;;;;wBAGIjK,I;;;;;;;;;;;;;;;;;;;+EAGED,G;;;;;;;wBAEW,KAAK1C,GAAL,CAAS0B,EAAT,CAAYmJ,GAAZ,CAAgBgC,OAAhB,E;;;AAAbC,qB;;AACNpK,qBAAI0C,IAAJ,GAAW,EAAE0H,UAAF,EAAX;AACApK,qBAAI8C,MAAJ,GAAa,GAAb;;;;;;;;;;;;;;;;;;;+EAGS9C,G;;;;;;AACH0C,qB,GAAO,KAAK2H,OAAL,CAAa3H,I;;AAC1BA,sBAAKoG,SAAL,GAAiB,KAAKuB,OAAL,CAAaC,MAAb,CAAoB,YAApB,CAAjB;;wBACkB,KAAKhN,GAAL,CAAS0B,EAAT,CAAYmJ,GAAZ,CAAgBoC,MAAhB,CAAuB7H,IAAvB,C;;;AAAZpF,oB;;AACN0C,qBAAI0C,IAAJ,GAAW,EAAEpF,QAAF,EAAX;AACA0C,qBAAI8C,MAAJ,GAAa,GAAb;;;;;;;;;;;;;;;;;;;;;KAIS0H,U,WAAAA,U;AACX,uBAAYlN,GAAZ,EAAiB;AAAA;;AACf,UAAKA,GAAL,GAAWA,GAAX;AACA,UAAKuD,KAAL,GAAa,WAAb;AACD;;;;;+EAEiBb,G,EAAKC,I;;;;;;AACrB,sBAAK2J,UAAL,CAAgB,UAAhB,EAA4BF,QAA5B,GAAuCG,KAAvC,CAA6C,uCAA7C;AACA,sBAAKD,UAAL,CAAgB,KAAhB,EAAuBF,QAAvB,GAAkCd,GAAlC,CAAsC,CAAtC,EAAyC,GAAzC;;sBACI,KAAKkB,M;;;;;AACD9G,sB,GAAQuG,KAAKQ,OAAL,CAAa,iBAAb,EAAgC,KAAKD,MAArC,C;;AACd9J,qBAAI8C,MAAJ,GAAa,GAAb;AACA9C,qBAAI0C,IAAJ,GAAWM,MAAMgH,MAAN,CAAaC,OAAxB;AACAjK,qBAAI0C,IAAJ,CAASwH,IAAT,GAAgBlH,MAAMkH,IAAtB;;;;;wBAGIjK,I;;;;;;;;;;;;;;;;;;;+EAGED,G;;;;;;;wBACU,KAAK1C,GAAL,CAAS0B,EAAT,CAAYmJ,GAAZ,CAAgBsC,QAAhB,CAAyB,KAAKC,MAAL,CAAYC,EAArC,C;;;AAAZrN,oB;;qBACDA,G;;;;;AACH0C,qBAAI8C,MAAJ,GAAa,GAAb;;;;AAGF9C,qBAAI0C,IAAJ,GAAW,EAAEpF,QAAF,EAAX;AACA0C,qBAAI8C,MAAJ,GAAa,GAAb;;;;;;;;;;;;;;;;;;;+EAGQ9C,G;;;;;;AACF0C,qB,GAAO,KAAK2H,OAAL,CAAa3H,I;;wBACR,KAAKpF,GAAL,CAAS0B,EAAT,CAAYmJ,GAAZ,CAAgBsC,QAAhB,CAAyB,KAAKC,MAAL,CAAYC,EAArC,C;;;AAAZrN,oB;;qBACDA,G;;;;;AACH0C,qBAAI8C,MAAJ,GAAa,GAAb;;;;;wBAIuBxF,IAAIsN,gBAAJ,CAAqBlI,IAArB,C;;;AAAnBmI,2B;;AACN7K,qBAAI0C,IAAJ,GAAW,EAAEpF,KAAKuN,UAAP,EAAX;AACA7K,qBAAI8C,MAAJ,GAAa,GAAb;;;;;;;;;;;;;;;;;;;+EAGW9C,G;;;;;;;wBACO,KAAK1C,GAAL,CAAS0B,EAAT,CAAYmJ,GAAZ,CAAgBsC,QAAhB,CAAyB,KAAKC,MAAL,CAAYC,EAArC,C;;;AAAZrN,oB;;qBACDA,G;;;;;AACH0C,qBAAI8C,MAAJ,GAAa,GAAb;;;;;wBAIIxF,IAAIwN,OAAJ,E;;;AACN9K,qBAAI8C,MAAJ,GAAa,GAAb;;;;;;;;;;;;;;;;;;;;;;;;;ACxFJ,kC","file":"marathon.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 22707473342d92570c95","module.exports = require(\"babel-polyfill\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"babel-polyfill\"\n// module id = 1\n// module chunks = 0","import program from 'commander'\nimport StartCmd from './cmd/start'\nimport { version } from './extensions/version'\n\nexport default class RootCmd {\n constructor() {\n this.rootCmd = program\n .version(version)\n }\n\n run(args) {\n this.rootCmd.parse(args)\n }\n}\n\nif (!module.parent) {\n const cmd = new RootCmd()\n new StartCmd(cmd.rootCmd) //eslint-disable-line\n cmd.run(process.argv)\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/index.js","module.exports = function(module) {\n\tif(!module.webpackPolyfill) {\n\t\tmodule.deprecate = function() {};\n\t\tmodule.paths = [];\n\t\t// module.parent = undefined by default\n\t\tmodule.children = [];\n\t\tmodule.webpackPolyfill = 1;\n\t}\n\treturn module;\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// (webpack)/buildin/module.js\n// module id = 3\n// module chunks = 0","module.exports = require(\"commander\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"commander\"\n// module id = 4\n// module chunks = 0","import config from 'config'\nimport MarathonApp from '../api/app'\n\nexport default class StartCmd {\n constructor(rootCmd) {\n rootCmd\n .command('start')\n .description('Start API')\n .action(() => {\n const app = new MarathonApp(config)\n app.run()\n })\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/cmd/start.js","module.exports = require(\"config\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"config\"\n// module id = 6\n// module chunks = 0","import { camelize } from 'humps'\nimport path from 'path'\nimport koaValidate from 'koa-validate'\nimport Koa from 'koa'\nimport _ from 'koa-route'\nimport Logger from '../extensions/logger'\nimport HealthcheckHandler from './handlers/healthcheck'\nimport { AppHandler, AppsHandler } from './handlers/app'\nimport { connect as redisConnect } from '../extensions/redis'\nimport { connect as pgConnect } from '../extensions/postgresql'\nimport { connect as kafkaClientConnect } from '../extensions/kafkaClient'\nimport { connect as kafkaProducerConnect } from '../extensions/kafkaProducer'\n\n\nexport default class MarathonApp {\n constructor(config) {\n this.config = config\n this.allowedMethods = ['get', 'post', 'put', 'delete']\n this.koaApp = new Koa()\n this.configureLogger()\n this.configureMiddleware()\n\n this.handlersPath = path.join(__dirname, '../api/handlers')\n this.handlers = this.getHandlers()\n this.redisConfig = config.get('app.services.redis')\n this.pgConfig = config.get('app.services.postgresql')\n }\n\n getHandlers() {\n const self = this\n const handlers = []\n\n // Include handlers here in the order the routes are supposed to be handled\n // example that will be resolved correctly:\n // GET /healthcheck/me\n // GET /healthcheck/:param\n // example that will be resolved incorrectly:\n // GET /healthcheck/:param\n // GET /healthcheck/me\n handlers.push(new HealthcheckHandler(self))\n handlers.push(new AppsHandler(self))\n handlers.push(new AppHandler(self))\n\n return handlers\n }\n\n exit(err) {\n if (process.env.NODE_ENV === 'test') {\n throw err\n }\n this.logger.fatal({ err })\n process.exit(1)\n }\n\n configureLogger() {\n this.logger = new Logger(this.config).logger.child({\n source: 'app',\n })\n }\n\n async configureRedis() {\n const redisOptions = {\n db: this.redisConfig.db,\n shouldReconnect: this.redisConfig.shouldReconnect,\n password: this.redisConfig.password,\n }\n if (!redisOptions.password) delete redisOptions.password\n try {\n this.redisClient = await redisConnect(\n this.redisConfig.url,\n redisOptions,\n this.logger\n )\n } catch (err) {\n this.exit(err)\n }\n }\n\n async configurePostgreSQL() {\n try {\n this.db = await pgConnect(\n this.pgConfig.url,\n this.pgConfig.options,\n this.logger\n )\n } catch (err) {\n this.exit(err)\n }\n }\n\n async configureKafka() {\n try {\n this.logger.debug('Connecting API Kafka client...')\n const cfg = this.config.get('app.services.kafka.api.client')\n this.apiKafkaClient = await kafkaClientConnect(cfg.url, cfg.clientId, this.logger)\n\n this.logger.debug('Connecting API Kafka producer...')\n const producerCfg = this.config.get('app.services.kafka.api.producer')\n this.apiKafkaProducer = await kafkaProducerConnect(\n this.apiKafkaClient,\n producerCfg,\n this.logger\n )\n } catch (err) {\n this.exit(err)\n }\n }\n\n async initializeServices() {\n try {\n this.logger.debug('Starting redis configuration...')\n await this.configureRedis()\n this.logger.debug('Starting PostgreSQL configuration...')\n await this.configurePostgreSQL()\n this.logger.debug('Starting Kafka configuration...')\n await this.configureKafka()\n } catch (err) {\n this.exit(err)\n }\n }\n\n configureMiddleware() {\n this.koaApp.use(async (ctx, next) => {\n const start = new Date()\n await next()\n const ms = new Date() - start\n ctx.set('X-Response-Time', `${ms}ms`)\n })\n koaValidate(this.koaApp)\n }\n\n async initializeApp() {\n await this.initializeServices()\n this.handlers.forEach((handler) => {\n this.allowedMethods.forEach((methodName) => {\n if (!handler[methodName]) {\n return\n }\n const handlerMethod = handler[methodName].bind(handler)\n const method = _[methodName]\n const args = [handler.route]\n const validate = handler[camelize(`validate_${methodName}`)]\n if (validate) {\n args.push(validate)\n }\n args.push(async (ctx) => {\n await handlerMethod(ctx)\n })\n\n this.koaApp.use(method.apply(handler, args))\n })\n })\n }\n\n async run() {\n const PORT = this.config.get('app.port')\n await this.initializeApp()\n\n this.logger.info(`Listening on port ${PORT}...`)\n this.koaApp.listen(PORT)\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/api/app.js","module.exports = require(\"humps\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"humps\"\n// module id = 8\n// module chunks = 0","module.exports = require(\"path\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"path\"\n// module id = 9\n// module chunks = 0","module.exports = require(\"koa-validate\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"koa-validate\"\n// module id = 10\n// module chunks = 0","module.exports = require(\"koa\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"koa\"\n// module id = 11\n// module chunks = 0","module.exports = require(\"koa-route\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"koa-route\"\n// module id = 12\n// module chunks = 0","import bunyan from 'bunyan'\nimport version from '../extensions/version'\n\nexport default class Logger {\n constructor(config) {\n this.config = config\n this.logLevel = config.get('app.log.level')\n this.logToStdOut = this.config.get('app.log.logToStdOut')\n this.logToFile = this.config.get('app.log.logToFile')\n this.logFile = this.config.get('app.log.file')\n this.configureLogger()\n }\n\n getStreams() {\n const streams = []\n if (this.logToStdOut) {\n streams.push({\n stream: process.stdout,\n level: this.logLevel,\n })\n }\n if (this.logToFile) {\n streams.push({\n path: this.logFile,\n level: this.logLevel,\n })\n }\n return streams\n }\n\n configureLogger() {\n this.logger = bunyan.createLogger({\n name: this.config.get('app.name'),\n src: false,\n streams: this.getStreams(),\n serializers: { err: bunyan.stdSerializers.err },\n }).child({ version }, true)\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/extensions/logger.js","module.exports = require(\"bunyan\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"bunyan\"\n// module id = 14\n// module chunks = 0","import pjson from '../../package.json'\n\nconst version = pjson.version\n\nexport default version\n\n\n\n// WEBPACK FOOTER //\n// ./src/extensions/version.js","module.exports = {\n\t\"name\": \"marathon\",\n\t\"version\": \"0.1.0\",\n\t\"description\": \"Marathon push processing system\",\n\t\"main\": \"src/index.js\",\n\t\"scripts\": {\n\t\t\"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n\t},\n\t\"repository\": {\n\t\t\"type\": \"git\",\n\t\t\"url\": \"git@git.topfreegames.com:topfreegames/marathon.git\"\n\t},\n\t\"author\": \"TFG Co\",\n\t\"license\": \"ISC\",\n\t\"devDependencies\": {\n\t\t\"babel-cli\": \"^6.16.0\",\n\t\t\"babel-core\": \"^6.17.0\",\n\t\t\"babel-istanbul\": \"^0.11.0\",\n\t\t\"babel-loader\": \"^6.2.5\",\n\t\t\"babel-plugin-syntax-async-functions\": \"^6.13.0\",\n\t\t\"babel-plugin-transform-async-to-generator\": \"^6.16.0\",\n\t\t\"babel-plugin-transform-regenerator\": \"^6.16.1\",\n\t\t\"babel-plugin-transform-runtime\": \"^6.15.0\",\n\t\t\"babel-polyfill\": \"^6.16.0\",\n\t\t\"babel-preset-es2015\": \"^6.16.0\",\n\t\t\"babel-register\": \"^6.16.3\",\n\t\t\"chai\": \"^3.5.0\",\n\t\t\"chai-http\": \"^3.0.0\",\n\t\t\"coveralls\": \"^2.11.14\",\n\t\t\"dirty-chai\": \"^1.2.2\",\n\t\t\"eslint\": \"^3.9.1\",\n\t\t\"eslint-config-airbnb-base\": \"^8.0.0\",\n\t\t\"eslint-plugin-import\": \"^1.16.0\",\n\t\t\"flow-bin\": \"^0.34.0\",\n\t\t\"graceful-fs\": \"^4.1.10\",\n\t\t\"istanbul\": \"^0.4.5\",\n\t\t\"mocha\": \"^3.1.2\",\n\t\t\"mocha-lcov-reporter\": \"^1.2.0\",\n\t\t\"plato\": \"^1.7.0\",\n\t\t\"stylish\": \"^1.0.0\",\n\t\t\"stylus\": \"^0.54.5\",\n\t\t\"supertest\": \"^2.0.0\",\n\t\t\"supertest-as-promised\": \"^4.0.0\",\n\t\t\"uuid\": \"^2.0.3\",\n\t\t\"webpack\": \"^1.13.2\"\n\t},\n\t\"dependencies\": {\n\t\t\"babel-runtime\": \"^6.11.6\",\n\t\t\"bluebird\": \"^3.4.6\",\n\t\t\"boom\": \"^4.2.0\",\n\t\t\"bufferutil\": \"^1.2.1\",\n\t\t\"bunyan\": \"^1.8.1\",\n\t\t\"commander\": \"^2.9.0\",\n\t\t\"config\": \"^1.21.0\",\n\t\t\"humps\": \"^2.0.0\",\n\t\t\"js-yaml\": \"^3.6.1\",\n\t\t\"json-loader\": \"^0.5.4\",\n\t\t\"kafka-node\": \"^1.0.5\",\n\t\t\"koa\": \"^2.0.0-alpha.7\",\n\t\t\"koa-route\": \"^3.2.0\",\n\t\t\"koa-validate\": \"^1.0.7\",\n\t\t\"mongoose\": \"^4.6.5\",\n\t\t\"pg\": \"^6.1.0\",\n\t\t\"pg-hstore\": \"^2.3.2\",\n\t\t\"pg-native\": \"^1.10.0\",\n\t\t\"redis\": \"^2.6.2\",\n\t\t\"redis-info\": \"^3.0.6\",\n\t\t\"redlock\": \"^2.0.1\",\n\t\t\"sequelize\": \"^3.24.7\",\n\t\t\"utf-8-validate\": \"^1.2.1\",\n\t\t\"validator\": \"^6.0.0\"\n\t},\n\t\"bin\": {\n\t\t\"marathon\": \"./lib/marathon.js\"\n\t}\n};\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./package.json\n// module id = 16\n// module chunks = 0","import { check as redisCheck } from '../../extensions/redis'\nimport { check as pgCheck } from '../../extensions/postgresql'\nimport { check as kafkaClientCheck } from '../../extensions/kafkaClient'\nimport { check as kafkaProducerCheck } from '../../extensions/kafkaProducer'\n\nexport default class HealthcheckHandler {\n constructor(app) {\n this.app = app\n this.route = '/healthcheck'\n this.resetServices()\n }\n\n resetServices() {\n this.services = {\n redis: { up: false },\n postgreSQL: { up: false },\n apiKafkaClient: { up: false },\n apiKafkaProducer: { up: false },\n }\n }\n\n hasFailed() {\n return (\n !this.services.redis.up ||\n !this.services.postgreSQL.up ||\n !this.services.apiKafkaClient.up ||\n !this.services.apiKafkaProducer.up\n )\n }\n\n async get(ctx) {\n this.services.redis = await redisCheck(this.app.redisClient)\n this.services.postgreSQL = await pgCheck(this.app.db)\n this.services.apiKafkaClient = await kafkaClientCheck(this.app.apiKafkaClient)\n this.services.apiKafkaProducer = await kafkaProducerCheck(this.app.apiKafkaProducer)\n ctx.body = JSON.stringify(this.services)\n\n if (this.hasFailed()) {\n ctx.status = 500\n }\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/api/handlers/healthcheck.js","import redis from 'redis'\nimport bluebird from 'bluebird'\nimport parser from 'redis-info'\nimport Redlock from 'redlock'\n\nbluebird.promisifyAll(redis.RedisClient.prototype)\nbluebird.promisifyAll(redis.Multi.prototype)\n\nlet Lock = null\nexport const LockKey = 'lock::matchmaking'\nexport const LockTTL = 100\n\nexport async function check(redisClient) {\n const result = {\n up: false,\n error: null,\n uptime: null,\n connectedClients: null,\n blockedClients: null,\n usedMemory: null,\n totalSystemMemory: null,\n maxMemory: null,\n rejectedConnections: 0,\n cpuUsage: 0,\n }\n\n try {\n const res = await redisClient.infoAsync()\n if (res) {\n const info = parser.parse(res)\n result.up = true\n result.uptime = info.uptime_in_seconds\n result.connectedClients = info.connected_clients\n result.blockedClients = info.blocked_clients\n result.usedMemory = info.used_memory_human\n result.totalSystemMemory = info.total_system_memory_human\n result.maxMemory = info.maxmemory_human\n result.rejectedConnections = info.rejected_connections\n result.cpuUsage = info.used_cpu_user\n } else {\n result.error = 'Could not get server status!'\n }\n } catch (error) {\n result.error = error.message\n }\n\n return result\n}\n\nexport async function connect(redisUrl, options, logger) {\n const logr = logger.child({\n redisUrl,\n options,\n source: 'redis-extension',\n })\n logr.debug({ redisUrl, options }, 'connecting to redis...')\n if (!options.shouldReconnect) {\n options.retry_strategy = () => undefined\n }\n const redisClient = redis.createClient(redisUrl, options)\n\n const hasConnected = new Promise((resolve, reject) => {\n if (redisClient.ready) {\n resolve(redisClient)\n return\n }\n\n redisClient.on('ready', () => {\n logr.debug('Connection to redis has been established successfully.')\n resolve(redisClient)\n })\n\n redisClient.on('error', (err) => {\n logr.error({ err }, 'Redis error connecting.')\n reject(err)\n })\n\n redisClient.on('end', () => {\n logr.error('Redis connection closed.')\n reject(new Error('Redis connection closed.'))\n })\n })\n\n await hasConnected\n\n const result = await redisClient.pingAsync()\n if (!result) {\n throw new Error('Failed to get server status from redis.')\n }\n logr.info({ redisUrl }, 'Successfully connected to redis.')\n return redisClient\n}\n\nexport async function withCriticalSection(redisClient, f) {\n if (!Lock) {\n const options = { retryCount: 50, retryDelay: 10 }\n Lock = new Redlock([redisClient], options)\n }\n const rlock = await Lock.lock(LockKey, LockTTL)\n const res = await f()\n await rlock.unlock()\n return res\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/extensions/redis.js","module.exports = require(\"redis\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"redis\"\n// module id = 19\n// module chunks = 0","module.exports = require(\"bluebird\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"bluebird\"\n// module id = 20\n// module chunks = 0","module.exports = require(\"redis-info\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"redis-info\"\n// module id = 21\n// module chunks = 0","module.exports = require(\"redlock\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"redlock\"\n// module id = 22\n// module chunks = 0","import Sequelize from 'sequelize'\nimport models from '../models/index'\n\nexport async function check(db) {\n const result = {\n up: false,\n }\n\n try {\n const query = \"select * from pg_stat_activity where state='active';\"\n const deadlockQuery = 'SELECT blocked_locks.pid AS blocked_pid, ' +\n 'blocked_locks.virtualtransaction as blocked_transaction_id, ' +\n 'blocked_activity.usename AS blocked_user, ' +\n 'blocking_locks.pid AS blocking_pid, ' +\n 'blocking_locks.virtualtransaction as blocking_transaction_id, ' +\n 'blocking_activity.usename AS blocking_user, ' +\n 'blocked_activity.query AS blocked_statement, ' +\n 'blocking_activity.query AS blocking_statement ' +\n 'FROM pg_catalog.pg_locks blocked_locks ' +\n 'JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid ' +\n 'JOIN pg_catalog.pg_locks blocking_locks ' +\n 'ON blocking_locks.locktype = blocked_locks.locktype ' +\n 'AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE ' +\n 'AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation ' +\n 'AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page ' +\n 'AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple ' +\n 'AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid ' +\n 'AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid ' +\n 'AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid ' +\n 'AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid ' +\n 'AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid ' +\n 'AND blocking_locks.pid != blocked_locks.pid ' +\n 'JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid ' +\n 'WHERE NOT blocked_locks.GRANTED; '\n const res = await db.client.query(query, { type: Sequelize.QueryTypes.SELECT })\n if (res) {\n result.activeOperations = res.length\n const deadlock = await db.client.query(deadlockQuery, { type: Sequelize.QueryTypes.SELECT })\n result.deadlock = deadlock.length === 0\n result.deadlockOperations = []\n deadlock.forEach((row) => {\n result.deadlockOperations.push({\n blocked: {\n pid: row.blocked_pid,\n txId: row.blocked_transaction_id,\n user: row.blocked_user,\n statement: row.blocked_statement,\n },\n blocking: {\n pid: row.blocking_pid,\n txId: row.blocking_transaction_id,\n user: row.blocking_user,\n statement: row.blocking_statement,\n },\n })\n })\n result.up = true\n } else {\n result.error = 'Could not get server status!'\n }\n } catch (error) {\n result.error = error.message\n }\n\n return result\n}\n\nexport async function connect(pgUrl, options, logger) {\n let opt = options\n if (!options) {\n opt = {}\n }\n\n const logr = logger.child({\n pgUrl,\n options,\n source: 'postgresql-extension',\n })\n opt.dialect = 'postgres'\n\n logr.debug({ pgUrl, opt }, 'Connecting to PostgreSQL...')\n\n try {\n const db = {}\n const client = new Sequelize(pgUrl, opt)\n const query = 'select 1;'\n const res = await client.query(query, { type: Sequelize.QueryTypes.SELECT })\n if (!res) {\n const err = new Error('Failed to connect to PostgreSQL.')\n logr.error({ pgUrl, err }, err.message)\n throw err\n }\n\n logr.debug('Loading models...')\n Object.keys(models).forEach((model) => {\n db[model] = models[model]\n logr.debug({ model }, 'Model loaded successfully.')\n })\n\n logr.debug('All models loaded successfully.')\n\n logr.debug('Loading model associations...')\n Object.keys(db).forEach((modelName) => {\n if (db[modelName].associate) {\n logr.debug({ modelName }, 'Loading model associations...')\n db[modelName].associate(db)\n logr.debug({ modelName }, 'Model associations loaded successfully.')\n }\n })\n\n db.client = client\n logger.info({ pgUrl }, 'Successfully connected to PostgreSQL.')\n return db\n } catch (err) {\n logger.error({ pgUrl, err }, 'Failed to connect to PostgreSQL.')\n throw err\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/extensions/postgresql.js","module.exports = require(\"sequelize\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"sequelize\"\n// module id = 24\n// module chunks = 0","import App from './app'\n\nconst models = {\n App,\n}\nexport default models\n\n\n\n// WEBPACK FOOTER //\n// ./src/models/index.js","const Sequelize = require('sequelize')\n\nmodule.exports = sequelize => (\n sequelize.define('app', {\n key: {\n type: Sequelize.STRING,\n allowNull: false,\n validate: { len: [1, 255] },\n },\n bundleId: {\n type: Sequelize.STRING,\n allowNull: false,\n validate: { len: [1, 2000] },\n },\n createdBy: {\n type: Sequelize.STRING,\n allowNull: false,\n validate: { len: [1, 2000] },\n },\n }, {\n timestamps: true,\n underscored: true,\n indexes: [\n { fields: ['key'], unique: true },\n ],\n })\n)\n\n\n\n// WEBPACK FOOTER //\n// ./src/models/app.js","import { Client } from 'kafka-node'\n\nexport async function check(kafkaClient) {\n const result = {\n up: kafkaClient.ready,\n error: null,\n }\n\n return result\n}\n\nexport async function connect(url, clientId, logger) {\n const logr = logger.child({\n url,\n clientId,\n source: 'kafka-client-extension',\n })\n logr.debug('Connecting to Kafka...')\n const kafkaClient = new Client(url, clientId)\n const hasConnected = new Promise((resolve, reject) => {\n kafkaClient.on('ready', () => {\n logr.debug('Kafka is ready.')\n resolve(kafkaClient)\n })\n kafkaClient.on('error', (err) => {\n logr.error({ err }, 'Failed to connect to kafka.')\n reject(err)\n })\n })\n\n logr.debug('Waiting for connection...')\n await hasConnected\n\n logr.info('Successfully connected to kafka.')\n return kafkaClient\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/extensions/kafkaClient.js","module.exports = require(\"kafka-node\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"kafka-node\"\n// module id = 28\n// module chunks = 0","import kafka from 'kafka-node'\n\nexport async function check(producer) {\n const result = {\n up: false,\n error: null,\n }\n\n try {\n result.up = producer.ready\n } catch (error) {\n result.error = error.message\n }\n\n return result\n}\n\nexport async function connect(client, options, logger) {\n const logr = logger.child({\n source: 'kafka-producer-extension',\n options,\n })\n logr.debug('Connecting to kafka producer...')\n const producer = new kafka.Producer(client, options)\n\n const hasConnected = new Promise((resolve, reject) => {\n if (producer.ready) {\n logr.debug('Connection to Kafka producer has been established successfully.')\n resolve(producer)\n return\n }\n\n producer.on('ready', () => {\n logr.debug('Connection to Kafka producer has been established successfully.')\n resolve(producer)\n })\n producer.on('error', (err) => {\n logr.error({ err }, 'Connection to Kafka producer failed.')\n reject(err)\n })\n })\n\n await hasConnected\n\n logr.info('Successfully connected to Kafka producer.')\n return producer\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/extensions/kafkaProducer.js","const Boom = require('boom')\n\nexport class AppsHandler {\n constructor(app) {\n this.app = app\n this.route = '/apps'\n }\n\n async validatePost(ctx, next) {\n this.checkHeaders('user-email').notEmpty().isEmail()\n this.checkQuery('bundleId').notEmpty().match(/^[a-z0-9]+\\.[a-z0-9]+(\\.[a-z0-9]+)+$/i)\n this.checkQuery('key').notEmpty().len(1, 255)\n if (this.errors) {\n const error = Boom.badData('wrong arguments', this.errors)\n ctx.status = 422\n ctx.body = error.output.payload\n ctx.body.data = error.data\n return\n }\n await next\n }\n\n async get(ctx) {\n // console.log(this.app.db)\n const apps = await this.app.db.App.findAll()\n ctx.body = { apps }\n ctx.status = 200\n }\n\n async post(ctx) {\n const body = this.request.body\n body.createdBy = this.request.header['user-email']\n const app = await this.app.db.App.create(body)\n ctx.body = { app }\n ctx.status = 201\n }\n}\n\nexport class AppHandler {\n constructor(app) {\n this.app = app\n this.route = '/apps/:id'\n }\n\n async validatePut(ctx, next) {\n this.checkQuery('bundleId').notEmpty().match(/^[a-z0-9]+\\.[a-z0-9]+(\\.[a-z0-9]+)+$/i)\n this.checkQuery('key').notEmpty().len(1, 255)\n if (this.errors) {\n const error = Boom.badData('wrong arguments', this.errors)\n ctx.status = 422\n ctx.body = error.output.payload\n ctx.body.data = error.data\n return\n }\n await next\n }\n\n async get(ctx) {\n const app = await this.app.db.App.findById(this.params.id)\n if (!app) {\n ctx.status = 404\n return\n }\n ctx.body = { app }\n ctx.status = 200\n }\n\n async put(ctx) {\n const body = this.request.body\n const app = await this.app.db.App.findById(this.params.id)\n if (!app) {\n ctx.status = 404\n return\n }\n\n const updatedApp = await app.updateAttributes(body)\n ctx.body = { app: updatedApp }\n ctx.status = 200\n }\n\n async delete(ctx) {\n const app = await this.app.db.App.findById(this.params.id)\n if (!app) {\n ctx.status = 404\n return\n }\n\n await app.destroy()\n ctx.status = 204\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/api/handlers/app.js","module.exports = require(\"boom\");\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"boom\"\n// module id = 31\n// module chunks = 0"],"sourceRoot":""} \ No newline at end of file diff --git a/migrations/20161103221706-creating app model.js b/migrations/20161103221706-creating app model.js index b2463980..a70e6d55 100644 --- a/migrations/20161103221706-creating app model.js +++ b/migrations/20161103221706-creating app model.js @@ -1,6 +1,6 @@ module.exports = { up: (queryInterface, Sequelize) => { - const App = queryInterface.createTable('app', { + const App = queryInterface.createTable('apps', { id: { type: Sequelize.INTEGER, primaryKey: true, @@ -37,5 +37,5 @@ module.exports = { }, down: queryInterface => - queryInterface.dropTable('app'), + queryInterface.dropTable('apps'), } diff --git a/package.json b/package.json index 6f66e86c..77a61f33 100644 --- a/package.json +++ b/package.json @@ -47,15 +47,19 @@ "dependencies": { "babel-runtime": "^6.11.6", "bluebird": "^3.4.6", + "boom": "^4.2.0", "bufferutil": "^1.2.1", "bunyan": "^1.8.1", "commander": "^2.9.0", "config": "^1.21.0", + "humps": "^2.0.0", "js-yaml": "^3.6.1", "json-loader": "^0.5.4", "kafka-node": "^1.0.5", "koa": "^2.0.0-alpha.7", - "koa-route": "^3.2.0", + "koa-bodyparser": "^3.2.0", + "koa-router": "^7.0.1", + "koa-validate": "^1.0.7", "mongoose": "^4.6.5", "pg": "^6.1.0", "pg-hstore": "^2.3.2", diff --git a/src/api/app.js b/src/api/app.js index cc1c626e..2de21bc9 100644 --- a/src/api/app.js +++ b/src/api/app.js @@ -1,7 +1,11 @@ +import { camelize } from 'humps' +import koaBodyparser from 'koa-bodyparser' +import koaRouter from 'koa-router' +import koaValidate from 'koa-validate' import path from 'path' import Koa from 'koa' -import _ from 'koa-route' import Logger from '../extensions/logger' +import { AppHandler, AppsHandler } from './handlers/app' import HealthcheckHandler from './handlers/healthcheck' import { connect as redisConnect } from '../extensions/redis' import { connect as pgConnect } from '../extensions/postgresql' @@ -29,6 +33,8 @@ export default class MarathonApp { // Include handlers here handlers.push(new HealthcheckHandler(self)) + handlers.push(new AppsHandler(self)) + handlers.push(new AppHandler(self)) return handlers } @@ -109,30 +115,39 @@ export default class MarathonApp { } configureMiddleware() { + this.koaApp.use(koaBodyparser()) this.koaApp.use(async (ctx, next) => { const start = new Date() await next() const ms = new Date() - start ctx.set('X-Response-Time', `${ms}ms`) }) + koaValidate(this.koaApp) } async initializeApp() { await this.initializeServices() + const router = koaRouter() this.handlers.forEach((handler) => { this.allowedMethods.forEach((methodName) => { if (!handler[methodName]) { return } const handlerMethod = handler[methodName].bind(handler) - const method = _[methodName] - this.koaApp.use( - method(handler.route, async (ctx) => { - await handlerMethod(ctx) - }) - ) + const method = router[methodName] + const args = [handler.route] + const validateName = camelize(`validate_${methodName}`) + if (handler[validateName]) { + args.push(handler[validateName].bind(handler)) + } + args.push(async (ctx) => { + await handlerMethod.apply(handler, [ctx]) + }) + method.apply(router, args) }) }) + this.koaApp.use(router.routes()) + this.koaApp.use(router.allowedMethods()) } async run() { diff --git a/src/api/handlers/app.js b/src/api/handlers/app.js new file mode 100644 index 00000000..53b7350a --- /dev/null +++ b/src/api/handlers/app.js @@ -0,0 +1,90 @@ +const Boom = require('boom') + +export class AppsHandler { + constructor(app) { + this.app = app + this.route = '/apps' + } + + async validatePost(ctx, next) { + ctx.checkHeader('user-email').notEmpty().isEmail() + ctx.checkBody('bundleId').notEmpty().match(/^[a-z0-9]+\.[a-z0-9]+(\.[a-z0-9]+)+$/i) + ctx.checkBody('key').notEmpty().len(1, 255) + if (ctx.errors) { + const error = Boom.badData('wrong arguments', ctx.errors) + ctx.status = 422 + ctx.body = error.output.payload + ctx.body.data = error.data + return + } + await next() + } + + async get(ctx) { + const apps = await this.app.db.App.findAll() + ctx.body = { apps } + ctx.status = 200 + } + + async post(ctx) { + const body = ctx.request.body + body.createdBy = ctx.request.header['user-email'] + const app = await this.app.db.App.create(body) + ctx.body = { app } + ctx.status = 201 + } +} + +export class AppHandler { + constructor(app) { + this.app = app + this.route = '/apps/:id' + } + + async validatePut(ctx, next) { + ctx.checkBody('bundleId').notEmpty().match(/^[a-z0-9]+\.[a-z0-9]+(\.[a-z0-9]+)+$/i) + ctx.checkBody('key').notEmpty().len(1, 255) + if (ctx.errors) { + const error = Boom.badData('wrong arguments', ctx.errors) + ctx.status = 422 + ctx.body = error.output.payload + ctx.body.data = error.data + return + } + await next() + } + + async get(ctx) { + const app = await this.app.db.App.findById(this.params.id) + if (!app) { + ctx.status = 404 + return + } + ctx.body = { app } + ctx.status = 200 + } + + async put(ctx) { + const body = ctx.request.body + const app = await this.app.db.App.findById(this.params.id) + if (!app) { + ctx.status = 404 + return + } + + const updatedApp = await app.updateAttributes(body) + ctx.body = { app: updatedApp } + ctx.status = 200 + } + + async delete(ctx) { + const app = await this.app.db.App.findById(this.params.id) + if (!app) { + ctx.status = 404 + return + } + + await app.destroy() + ctx.status = 204 + } +} diff --git a/src/extensions/postgresql.js b/src/extensions/postgresql.js index 507fe085..5e20a5cb 100644 --- a/src/extensions/postgresql.js +++ b/src/extensions/postgresql.js @@ -92,9 +92,9 @@ export async function connect(pgUrl, options, logger) { } logr.debug('Loading models...') - models.forEach((model) => { - db[model.name] = model - logr.debug({ model: model.name }, 'Model loaded successfully.') + Object.keys(models).forEach((model) => { + db[model] = models[model](client, Sequelize.DataTypes) + logr.debug({ model }, 'Model loaded successfully.') }) logr.debug('All models loaded successfully.') diff --git a/src/models/index.js b/src/models/index.js index 22509f82..686b4492 100644 --- a/src/models/index.js +++ b/src/models/index.js @@ -1,6 +1,6 @@ import App from './app' -const models = [ +const models = { App, -] +} export default models diff --git a/test/unit/api/handlers/appTest.js b/test/unit/api/handlers/appTest.js new file mode 100644 index 00000000..ea1844b9 --- /dev/null +++ b/test/unit/api/handlers/appTest.js @@ -0,0 +1,145 @@ +import { expect } from '../../common' +import uuid from 'uuid' + +describe('Handlers', () => { + describe('Apps Handler', () => { + describe('GET', () => { + it('should return 200 and an empty list of apps if there are no apps', async function () { + await this.app.db.App.destroy({ truncate: true }) + const res = await this.request.get('/apps') + expect(res.status).to.equal(200) + + const body = res.body + expect(body).to.be.an('object') + + expect(body.apps).to.exist() + expect(body.apps).to.have.length(0) + }) + + it('should return 200 and a list of apps', async function () { + const app = { + key: uuid.v4(), + bundleId: 'com.app.my', + createdBy: 'someone@somewhere.com', + } + await this.app.db.App.create(app) + const res = await this.request.get('/apps') + expect(res.status).to.equal(200) + + const body = res.body + expect(body).to.be.an('object') + + expect(body.apps).to.exist() + expect(body.apps).to.have.length.at.least(1) + + const myApp = body.apps.filter(a => a.key === app.key)[0] + expect(myApp).to.exist() + expect(myApp.key).to.equal(app.key) + expect(myApp.bundleId).to.equal(app.bundleId) + expect(myApp.createdBy).to.equal(app.createdBy) + }) + }) + + describe('POST', () => { + let app + let userEmail + + beforeEach(() => { + app = { + key: uuid.v4(), + bundleId: 'com.app.my', + } + userEmail = 'someone@somewhere.com' + }) + + it('should return 201 and the created app', async function () { + const res = await this.request.post('/apps').send(app).set('user-email', userEmail) + expect(res.status).to.equal(201) + + const body = res.body + expect(body).to.be.an('object') + + expect(body.app).to.exist() + expect(body.app).to.be.an('object') + + expect(body.app.key).to.equal(app.key) + expect(body.app.bundleId).to.equal(app.bundleId) + expect(body.app.createdBy).to.equal(userEmail) + }) + + describe('Should fail if missing', () => { + it('user-email header', async function () { + const res = await this.request.post('/apps').send(app) + expect(res.status).to.equal(422) + + const body = res.body + expect(body).to.be.an('object') + + expect(body.data).to.exist() + expect(body.data).to.have.length(1) + expect(body.data[0]).to.have.property('user-email') + expect(body.data[0]['user-email']).to.contain('empty') + }) + + const tests = [ + { args: 'key' }, + { args: 'bundleId' }, + ] + + tests.forEach((test) => { + it(test.args, async function () { + delete app[test.args] + const res = await this.request.post('/apps').send(app).set('user-email', userEmail) + expect(res.status).to.equal(422) + + const body = res.body + expect(body).to.be.an('object') + + expect(body.data).to.exist() + expect(body.data).to.have.length(1) + expect(body.data[0]).to.have.property(test.args) + expect(body.data[0][test.args]).to.contain('empty') + }) + }) + }) + + describe('Should fail if invalid', () => { + it('user-email header', async function () { + const res = await this.request.post('/apps').send(app).set('user-email', 'not an email') + expect(res.status).to.equal(422) + + const body = res.body + expect(body).to.be.an('object') + + expect(body.data).to.exist() + expect(body.data).to.have.length(1) + expect(body.data[0]).to.have.property('user-email') + expect(body.data[0]['user-email']).to.contain('email format') + }) + + const tests = [ + { args: 'key', invalidParam: '', reason: 'empty' }, + // { args: 'key', invalidParam: 'a'.repeat(256), reason: 'too long' }, + { args: 'bundleId', invalidParam: '', reason: 'empty' }, + { args: 'bundleId', invalidParam: 'a.s', reason: 'bad format.' }, + ] + + tests.forEach((test) => { + it(test.args, async function () { + app[test.args] = test.invalidParam + const res = await this.request.post('/apps').send(app).set('user-email', userEmail) + expect(res.status).to.equal(422) + + const body = res.body + expect(body).to.be.an('object') + + expect(body.data).to.exist() + expect(body.data).to.have.length(1) + expect(body.data[0]).to.have.property(test.args) + expect(body.data[0][test.args]).to.contain(test.reason) + }) + }) + }) + }) + }) +}) diff --git a/test/unit/common.js b/test/unit/common.js index fb0dcfbd..73130e12 100644 --- a/test/unit/common.js +++ b/test/unit/common.js @@ -16,7 +16,6 @@ beforeEach(async function () { config.app.port = PORT if (!app) { app = new MarathonApp(config) - await app.initializeApp() } this.app = app this.wssPort = PORT