bot18
Version:
A high-frequency cryptocurrency trading bot by Zenbot creator @carlos8f
158 lines (151 loc) • 4.44 kB
JavaScript
var pathRegExp = require('path-to-regexp')
, bladerunner = require('./')
, Runner
, methods = require('methods')
, url = require('url')
, minimatch = require('minimatch')
// Cached parsed urls.
function parseUrl (req) {
var parsed = req._parsedUrl;
if (parsed && parsed.href == req.url) return parsed;
return req._parsedUrl = url.parse(req.url);
};
// Global incremented id for sorting.
var globalId = 0;
function Route (args) {
this.weight = 0;
this.id = globalId++;
this.paths = [];
this.methods = [];
this.handlers = [];
this.options = {};
this.hosts = [];
var self = this;
[].slice.call(args).forEach(function (arg) {
if (typeof arg === 'object') {
// Route properties
arg = Object.keys(arg).map(function (k) {
return arg[k];
});
}
if (!Array.isArray(arg)) {
arg = [arg];
}
arg.forEach(function (arg) {
if (arg instanceof RegExp || (typeof arg === 'string' && arg[0] === '/')) {
// Implied path string/regex
self.paths.push(arg);
}
else if (typeof arg === 'number') {
// Implied weight
self.weight = arg;
}
else if (typeof arg === 'string') {
if (~methods.indexOf(arg.toLowerCase())) {
// HTTP method
self.methods.push(arg);
}
else {
// host matcher
self.hosts.push(arg);
}
}
else if (typeof arg === 'function') {
// handler
self.handlers.push(arg);
}
else if (toString.call(arg) === '[object Object]') {
Object.keys(arg).forEach(function (k) {
self.options[k] = arg[k];
});
}
});
});
this.methods = this.methods.map(function (method) {
return method.toUpperCase();
});
if (this.paths.length) {
this.paramses = [];
this.regexes = this.paths.map(function (p) {
var params = [];
self.paramses.push(params);
return pathRegExp(p, params, {strict: true, sensitive: true});
});
}
if (this.handlers.length === 1) {
this.handler = this.handlers[0];
}
else {
if (!Runner) Runner = require('./').Runner;
this.runner = new Runner();
this.handlers.forEach(function (handler) {
self.runner.add(handler);
});
this.handler = this.runner.handler;
}
// performance
this.methodCount = this.methods.length;
this.pathCount = this.paths.length;
this.hostCount = this.hosts.length;
}
module.exports = Route;
function inArray (val, arr, length, useMatch) {
if (!arr || !length) return false;
for (var idx = 0; idx < length; idx++) {
if (useMatch && minimatch(val, arr[idx])) return true;
if (arr[idx] === val) return true;
}
return false;
}
Route.prototype.match = function (req) {
var debug = require('debug')('bladerunner:route:match');
debug('matching', req.method, req.url, 'to', this.paths.join(','));
var customMatch = this.options.match && this.options.match.call(this, req);
if (customMatch !== null && customMatch !== false && typeof customMatch !== 'undefined') {
debug('custom match', req.method, req.url);
return customMatch;
}
if (this.methodCount && req.method !== 'HEAD' && !inArray(req.method, this.methods, this.methodCount)) {
debug('wrong method', req.method, req.url);
return false;
}
if (this.hostCount && req.headers && req.headers.host) {
if (!req._parsedHost) req._parsedHost = req.headers.host.split(':');
// minimatch
if (!inArray(req._parsedHost[0], this.hosts, this.hostCount, true)) {
debug('wrong method', req.method, req.url);
return false;
}
}
if (!this.pathCount) {
debug('match: no paths', req.method, req.url);
return true;
}
var reqPath = parseUrl(req).pathname;
// Exact match
if (inArray(reqPath, this.paths, this.pathCount)) {
debug('exact match', req.method, req.url);
return {};
}
var self = this;
for (var idx = 0; idx < this.pathCount; idx++) {
// Try the regex
var matches = this.regexes[idx].exec(reqPath);
if (!matches) continue;
matches.shift();
var params = [];
matches.forEach(function (val, idx2) {
var key = self.paramses[idx][idx2];
if (key) {
debug('param key', key);
params[key.name] = val;
}
else {
params.push(val);
}
});
debug('regex match', req.method, req.url, params);
return params;
}
return false;
};