-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(availity-mock-server): integrate mock server. Closes #127
- Loading branch information
Rob McGuinness
committed
Jan 2, 2018
1 parent
0683816
commit 79b156c
Showing
36 changed files
with
1,873 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
extends: availity | ||
rules: | ||
import/no-dynamic-require: 0 | ||
global-require: 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
const _ = require('lodash'); | ||
const chalk = require('chalk'); | ||
const logger = require('../logger').getInstance(); | ||
|
||
class Configuration { | ||
constructor() { | ||
this.server = null; | ||
this.app = null; | ||
this.router = null; | ||
this.routes = []; | ||
this.events = null; | ||
this.path = null; | ||
this.addressInUse = null; | ||
|
||
this.constants = { | ||
EVENTS: { | ||
START: 'av:started', | ||
STOPPED: 'av:stopped', | ||
REQUEST: 'av:request', | ||
RESPONSE: 'av:response', | ||
REDIRECT: 'av:redirect', | ||
FILE_NOT_FOUND: 'av:fileNotFound' | ||
} | ||
}; | ||
} | ||
|
||
/** | ||
* Set the path of the configuration object | ||
* | ||
* @param {Sring} path full path to configuration. Ex: path.join(__dirname, 'config.js') | ||
*/ | ||
|
||
defaultConfig(path) { | ||
return this.path ? require(path) : require('../config'); | ||
} | ||
|
||
/** | ||
* Sets the configuration object from the configuration file and command line overrides. | ||
* | ||
* @param {Object} options configuration object with production|development|testing settings. | ||
*/ | ||
set(_options) { | ||
const options = _options || {}; | ||
|
||
logger.setProvider(options.logProvider); | ||
|
||
// Get the config object by path or from root | ||
if (this.path) { | ||
logger.info(`Using ${chalk.blue(this.path)}`); | ||
} | ||
let config = this.path ? require(this.path) : this.defaultConfig(); | ||
|
||
// Allow programmatic overrides for environment | ||
config = _.merge(config, options); | ||
|
||
// Save to `this.options` | ||
this.options = config; | ||
} | ||
} | ||
|
||
module.exports = new Configuration(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/* eslint-disable promise/avoid-new */ | ||
const express = require('express'); | ||
const events = require('events'); | ||
const http = require('http'); | ||
const chalk = require('chalk'); | ||
const logger = require('./logger'); | ||
const config = require('./config'); | ||
const middleware = require('./middleware'); | ||
|
||
class Ekko { | ||
constructor(ekkoConfig) { | ||
if (ekkoConfig) { | ||
const isString = typeof ekkoConfig === 'string'; | ||
|
||
if (isString) { | ||
this.configPath = ekkoConfig; | ||
} else { | ||
this.middleware(ekkoConfig); | ||
} | ||
} | ||
|
||
config.events = new events.EventEmitter(); | ||
} | ||
|
||
middleware(options) { | ||
config.path = this.configPath; | ||
config.set(options); | ||
|
||
config.app = express(); | ||
config.router = new express.Router(); | ||
|
||
middleware.headers(); | ||
middleware.config(); | ||
|
||
return config.router; | ||
} | ||
|
||
async start(options) { | ||
this.middleware(options); | ||
|
||
const port = config.options.port || 0; | ||
config.app.set('port', port); | ||
config.server = http.createServer(config.app); | ||
|
||
return new Promise((resolve, reject) => { | ||
config.server.listen(config.options.port, () => { | ||
const url = `http://localhost:${config.server.address().port}`; | ||
logger.getInstance().info(`Ekko server started at ${chalk.green(url)}`); | ||
|
||
config.events.emit(config.constants.EVENTS.START, { | ||
options: config.options | ||
}); | ||
|
||
resolve(true); | ||
}); | ||
|
||
config.server.on('error', e => { | ||
if (e.errno === 'EADDRINUSE') { | ||
logger | ||
.getInstance() | ||
.error(`Cannot start Ekko server on PORT ${config.options.port}. Check if port is already in use.`); | ||
} else { | ||
logger.getInstance().error(`Failed to start Ekko server on PORT ${config.options.port}`); | ||
} | ||
|
||
reject(new Error(e)); | ||
}); | ||
}); | ||
} | ||
|
||
stop() { | ||
return new Promise(resolve => { | ||
if (config.server && config.server.close) { | ||
config.server.close(() => { | ||
config.events.emit(config.constants.EVENTS.STOPPED); | ||
resolve(true); | ||
}); | ||
} else { | ||
config.events.emit(config.constants.EVENTS.STOPPED); | ||
resolve(true); | ||
} | ||
}); | ||
} | ||
|
||
on(event, callback) { | ||
return config.events.on(event, callback); | ||
} | ||
|
||
config() { | ||
return config; | ||
} | ||
} | ||
|
||
module.exports = Ekko; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/* eslint no-console:0 */ | ||
const chalk = require('chalk'); | ||
|
||
let loggerInstance; | ||
|
||
class DefaultLogger { | ||
constructor(options) { | ||
this.options = options; | ||
} | ||
|
||
warn(entry) { | ||
this.record(entry, 'yellow'); | ||
} | ||
|
||
error(entry) { | ||
this.record(entry, 'red'); | ||
} | ||
|
||
info(entry) { | ||
this.record(entry); | ||
} | ||
|
||
debug(entry) { | ||
this.record(entry); | ||
} | ||
|
||
log(entry) { | ||
this.record(entry); | ||
} | ||
|
||
// › Starting server | ||
record(entry, color) { | ||
const defaultColor = entry instanceof Error ? 'red' : 'gray'; | ||
const crayoloa = color || defaultColor; | ||
|
||
console.log(`${chalk[crayoloa](entry)}`); | ||
} | ||
} | ||
|
||
class Logger { | ||
constructor() { | ||
this.provider = null; | ||
this.setProvider(() => new DefaultLogger()); | ||
} | ||
|
||
canLog() { | ||
return process.env.NODE_ENV !== 'testing'; | ||
} | ||
|
||
setProvider(fn) { | ||
if (fn) { | ||
this.provider = fn(); | ||
} | ||
} | ||
|
||
warn(entry) { | ||
if (this.canLog()) { | ||
this.provider.warn(entry); | ||
} | ||
} | ||
|
||
error(entry) { | ||
if (this.canLog()) { | ||
this.provider.error(entry); | ||
} | ||
} | ||
|
||
info(entry) { | ||
if (this.canLog()) { | ||
this.provider.info(entry); | ||
} | ||
} | ||
|
||
debug(entry) { | ||
if (this.canLog()) { | ||
this.provider.debug(entry); | ||
} | ||
} | ||
|
||
log(entry) { | ||
if (this.canLog()) { | ||
this.provider.log(entry); | ||
} | ||
} | ||
} | ||
|
||
module.exports = { | ||
// singleton | ||
getInstance() { | ||
if (!loggerInstance) { | ||
loggerInstance = new Logger(); | ||
} | ||
|
||
return loggerInstance; | ||
}, | ||
|
||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
const errorhandler = require('errorhandler'); | ||
const compression = require('compression'); | ||
const methodOverride = require('method-override'); | ||
const cors = require('cors'); | ||
const path = require('path'); | ||
const bodyParser = require('body-parser'); | ||
const busboy = require('connect-busboy'); | ||
const _ = require('lodash'); | ||
const onFinished = require('on-finished'); | ||
const chalk = require('chalk'); | ||
|
||
const config = require('../config'); | ||
const routes = require('../routes'); | ||
const logger = require('../logger').getInstance(); | ||
|
||
const requestHandler = require('./request'); | ||
const notFoundHandler = require('./not.found'); | ||
|
||
// Custom request logger | ||
module.exports = function development() { | ||
if (logger.canLog()) { | ||
config.router.use((req, res, next) => { | ||
function logRequest() { | ||
const method = `${chalk.white(req.method)}`; | ||
const url = `${chalk.dim(req.originalUrl || req.url)}`; | ||
// eslint-disable-next-line no-underscore-dangle | ||
const code = res._header ? String(res.statusCode) : ''; | ||
const file = chalk.dim(res.avFile || ''); | ||
|
||
logger.log(`${method} ${url} ${chalk.white(code)} ${chalk.blue(path.basename(file))}`); | ||
} | ||
|
||
// Callback is called at the end of request cycle after headers are set | ||
onFinished(res, logRequest); | ||
|
||
next(); | ||
}); | ||
} | ||
|
||
config.router.use(requestHandler()); | ||
config.router.use(errorhandler()); | ||
config.router.use(compression()); | ||
config.router.use(cors()); | ||
|
||
// pretty print json | ||
config.app.set('json spaces', 2); | ||
|
||
config.router.use(methodOverride('X-HTTP-Method-Override')); | ||
|
||
config.router.use( | ||
bodyParser.json({ | ||
limit: _.get(config, 'options.limit', '50mb') | ||
}) | ||
); // parse application/json | ||
|
||
config.router.use( | ||
bodyParser.urlencoded({ | ||
extended: true, | ||
limit: config.options.limit | ||
}) | ||
); // // parse application/x-www-form-urlencoded | ||
|
||
config.router.use(busboy({ immediate: false })); | ||
|
||
config.app.use('/', config.router); | ||
routes.init(); | ||
|
||
config.app.use(notFoundHandler()); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const config = require('../config'); | ||
|
||
module.exports = function headers() { | ||
config.app.disable('x-powered-by'); | ||
config.app.use((req, res, next) => { | ||
res.setHeader('X-Powered-By', 'Ekko'); | ||
next(); | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
const headers = require('./headers'); | ||
const config = require('./config'); | ||
|
||
module.exports = { | ||
headers, | ||
config | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
const config = require('../config'); | ||
|
||
module.exports = function notfound() { | ||
return (req, res) => { | ||
res.status(404); | ||
|
||
config.events.emit(config.constants.EVENTS.FILE_NOT_FOUND, { | ||
req | ||
}); | ||
|
||
const message = 'Not Found'; | ||
|
||
if (req.accepts('html')) { | ||
res | ||
.type('html') | ||
.status(404) | ||
.end( | ||
'<!DOCTYPE html> <html> <head> <title>Dummy Mock Server Response</title> </head> <body> <h1>Not Found<h1> </body> </html>' | ||
); | ||
return; | ||
} | ||
|
||
// respond with json | ||
if (req.accepts('json')) { | ||
res.type('json').send({ error: message }); | ||
return; | ||
} | ||
|
||
// respond with json | ||
if (req.accepts('xml')) { | ||
res.type('xml').send(`<error><message>${message}</message></error>`); | ||
return; | ||
} | ||
|
||
// default to plain-text. send() | ||
res.type('txt').send({ error: message }); | ||
}; | ||
}; |
Oops, something went wrong.