UNPKG

rocky

Version:

Full-featured, middleware-oriented, hackable HTTP and WebSocket proxy

314 lines (272 loc) 6.52 kB
const router = require('router') const Route = require('./route') const Base = require('./base') const server = require('./server') const assign = require('lodash').assign const toArray = require('./helpers').toArray const routeHandler = require('./protocols/http/route-handler') module.exports = Rocky /** * Rocky implements an HTTP and WebSocket proxy with built-in router * and hierarchical middleware layer. * * @param {Object} opts * @class Rocky * @extend Base * @constructor */ function Rocky (opts) { if (!(this instanceof Rocky)) return new Rocky(opts) opts = opts || {} Base.call(this, opts) this.server = null this.router = router(opts.router) this._setupMiddleware() } Rocky.prototype = Object.create(Base.prototype) /** * Define the proxy networking protocol. * Allowed protocols are `ws` and `http`. Defaults to `http`. * * @param {String} name * @return {Rocky} * @method protocol */ Rocky.prototype.protocol = function (name) { if (name === 'ws') this.opts.ws = true return this } /** * Attaches an middleware function to the HTTP incoming traffic phase. * Middleware will be globally executed and applies to any * HTTP request handled by the server. * * @param {String} path * @method use * @alias useIncoming * @return {Rocky} */ Rocky.prototype.use = Rocky.prototype.useIncoming = function () { this.router.use.apply(this.router, arguments) return this } /** * Attaches a path param based middleware function. * Middleware will be executed every time the given path * param is matched by the router. * * @param {String} param * @param {Function} middleware * @method param * @alias useParam * @return {Rocky} */ Rocky.prototype.param = Rocky.prototype.useParam = function (param, middleware) { this.router.param.apply(this.router, arguments) return this } /** * Attaches a middleware function for websocket data frames. * Only dispatched for websocket proxies. * * @param {Function} middleware * @return {Rocky} * @method useWs * @return {Rocky} */ Rocky.prototype.useWs = function (middleware) { this.useFor('ws', arguments) return this } /** * Exposes a connect/express compatible middleware function. * * @return {Function} * @method middleware */ Rocky.prototype.middleware = function () { return this.requestHandler.bind(this) } /** * Middleware function handler for incoming HTTP traffic. * This function will be triggered by the rocky router. * * Except in very specific scenarios, you don't need to use this method. * * @param {http.IncomingMessage} req * @param {http.ServerResponse} res * @param {Function} next * @return {Rocky} * @method requestHandler */ Rocky.prototype.requestHandler = function (req, res, next) { this.router(req, res, next || function () {}) return this } /** * Start listening on the network, optionally passing a * TCP port number and/or host to bind the connection.l * * @param {Number} port * @param {String} host * @return {Rocky} * @method listen */ Rocky.prototype.listen = function (port, host) { const opts = this.opts if (port) opts.port = port if (host) opts.host = host if (opts.ws) this.routeAll() this.server = server(this) return this } /** * Stop the server, optionally passing a callback to handle the status. * * @param {Function} done * @return {Rocky} * @method close */ Rocky.prototype.close = function (done) { if (this.server) { this.server.close(function (err) { this.server = null if (done) done(err) }.bind(this)) } return this } /** * Route all the incoming HTTP traffic for any route and any HTTP verb. * * @return {Route} * @method routeAll */ Rocky.prototype.routeAll = function () { return this.all('/*') } /** * Creates a new route for the given HTTP verb and path. * For better convenience you can use the verb specific method shortcuts. * * @param {String} method * @param {String} path * @return {Route} * @method route */ Rocky.prototype.route = function (method, path) { const route = new Route(path) route.proxy = this const handler = routeHandler(this, route) const middleware = [].slice.call(arguments, 1) const args = middleware.concat([ handler ]) this.router[method.toLowerCase()].apply(this.router, args) return route } /** * Creates a new HTTP route for GET requests and the given path. * * @param {String} path * @return {Route} * @method get * @name get * @memberof Rocky * @instance */ /** * Creates a new HTTP route for POST requests and the given path. * * @param {String} path * @return {Route} * @method post * @name post * @memberof Rocky * @instance */ /** * Creates a new HTTP route for PUT requests and the given path. * * @param {String} path * @return {Route} * @method put * @name put * @memberof Rocky * @instance */ /** * Creates a new HTTP route for DELETE requests and the given path. * * @param {String} path * @return {Route} * @method delete * @name delete * @memberof Rocky * @instance */ /** * Creates a new HTTP route for PATCH requests and the given path. * * @param {String} path * @return {Route} * @method patch * @name patch * @memberof Rocky * @instance */ /** * Creates a new HTTP route for HEAD requests and the given path. * * @param {String} path * @return {Route} * @method head * @name head * @memberof Rocky * @instance */ /** * Creates a new HTTP route for TRACE requests and the given path. * * @param {String} path * @return {Route} * @method trace * @name trace * @memberof Rocky * @instance */ /** * Creates a new HTTP route for any verb requests and the given path. * * @param {String} path * @return {Route} * @method all * @name all * @memberof Rocky * @instance */ ;['get', 'post', 'delete', 'patch', 'put', 'head', 'trace', 'all'].forEach(function (method) { Rocky.prototype[method] = function (path) { const args = [ method ].concat(toArray(arguments)) return this.route.apply(this, args) } }) /** * Set up generic built-in middleware function to the middleware stack. * * @method _setupMiddleware * @private */ Rocky.prototype._setupMiddleware = function () { const rocky = this function middleware (req, res) { const next = arguments[arguments.length - 1] const opts = assign({}, rocky.opts) req.rocky = { proxy: rocky, options: opts } next() } if (rocky.opts.ws) { return rocky.mw.use('ws', middleware) } rocky.router.use(middleware) }