Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions lib/commands/generateCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,8 @@ GenerateCommand.prototype.parseType = function(type) {
return commonTypes[type]
} else {
var matches = type.match(/\[([a-zA-Z]+)\]/)
console.log(matches)
if(matches) {
type = this.parseType(matches[1])
console.log("new type:", type)
return "[" + type + "]"
} else {
return "{ type: Schema.Types.ObjectId, ref: '" + _titlelize(type) + "' }"
Expand Down
26 changes: 12 additions & 14 deletions lib/handlerParser.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var logger = require("./logger"),
fs = require("fs"),
stripComments = require("strip-json-comments"),
_ = require("lodash");

var CONFIG_FILE_PATH = process.cwd() + "/vatican-conf.json";
Expand All @@ -14,35 +15,32 @@ module.exports = {
cb("Error reading folder: " + dir);
} else {
var fpath = "";
var regExp = /@endpoint\s*\((url:.+)\s*(method:(?:[ \t]*)(?:get|put|post|delete))\s*(name:.+)?\s*\)[\s\n]*([^\s]*)\.prototype\.([^\s]*)/gim

_(files).where(function(f) { return f.match(/\.js$/i); }).forEach(function(fname) {
fpath = dir + "/" + fname;
logger.info("Openning file: " + fpath);
var content = fs.readFileSync(fpath).toString();
var regExp = /@endpoint ?\((url:.+) (method: (?:get|put|post|delete)) ?(name:.+)?\).*\n(.*)\(/gim;
content = content.replace(/\/\/\s*@/g, "@") //We allow commenting the line of the endpoint for correct editor syntax coloring
content = stripComments(content) //we remove the comments so we don't deal with commented out endpoints

while( (matches = regExp.exec(content)) !== null) {
var params = _.compact(matches.slice(1,4))
var currentPath = {};
params.forEach(function(p) {
var parts = p.split(" ");
var key = parts[0].trim().replace(":", ""),
value = parts[1].trim();
var parts = p.split(":"),
key = parts.shift(),
value = parts.join(":").trim();
if(value)
currentPath[key] = value;
})
var actionStr = matches[4];

var actionStr = matches[5]
handlerName = matches[4]

if(actionStr.indexOf("=") !== -1) {
actionStr = actionStr.split("=")[0];
}
if(actionStr.indexOf(".") !== -1) {
actionParts = actionStr.split(".");
actionStr = actionParts.pop() //[actionStr.length - 1];
handlerName = actionParts.shift()
}
currentPath['action'] = actionStr.trim();
currentPath['handlerPath'] = fpath;
currentPath['handlerName'] = handlerName
currentPath.method = currentPath.method.toUpperCase()

paths.push(currentPath);
}
Expand Down
44 changes: 30 additions & 14 deletions lib/processingChain.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

var _ = require("lodash")

module.exports = ProcessingChain;

Expand All @@ -9,6 +9,9 @@ function ProcessingChain( ) {
}

ProcessingChain.prototype.add = function( proc ) {
proc.names = proc.names ?
( Array.isArray(proc.names) ? proc.names : Array(proc.names) )
: [];
if(proc.fn.length == 4) //it's an error handler
this.errorHandlers.push(proc);
else
Expand All @@ -23,9 +26,17 @@ ProcessingChain.prototype.pop = function() {
this.chain.pop();
}

ProcessingChain.prototype.runChain = function( req, res, finalFn, handler ) {
ProcessingChain.prototype.runChain = function( params ) {
params = params || {};
var req = params.req;
var res = params.res;
var finalFn = params.finalFn;
var handler = params.handler;
var endPrep = (params.endPrep && {fn: params.endPrep}) || []; //last preprocessor

var currentItem = 0;
var totalItems = this.chain.length;
var chain = [].concat(this.chain, endPrep);
var totalItems = chain.length;
var self = this;
if(totalItems == 0) {
if(typeof finalFn == 'function') finalFn(req, res);
Expand All @@ -35,25 +46,30 @@ ProcessingChain.prototype.runChain = function( req, res, finalFn, handler ) {
var nextError = function ( err ) {
if ( currentItem < totalItems - 1 ) {
currentItem++
self.errorHandlers[currentItem](err, req, res, nextError)
self.errorHandlers[currentItem].fn(err, req, res, nextError)
} else {
if(typeof finalFn == 'function') finalFn(req, res);
}
}

var next = function(err) {
var chain = self.chain;
//chain is taken from the closure
if ( err ) { //If there is an error, switch to the error handlers chain
chain = self.errorHandlers;
currentItem = -1;
totalItems = self.errorHandlers.length;
}
if ( currentItem < totalItems - 1 ) {
for(var idx = currentItem; idx < chain.length; idx++) {
if( (chain[idx].names && chain[idx].names.indexOf(handler.name) != -1) || !chain[idx].names) {
break
var idx = ++currentItem;

if( handler && handler.name) {
for(; idx < chain.length; idx++) {
if( !chain[idx].names || ( ! chain[idx].names.length ) || ~chain[idx].names.indexOf(handler.name)) {
break
}
}
}
}

currentItem = idx
if(err) {
chain[currentItem].fn(err, req, res, nextError)
Expand All @@ -65,16 +81,16 @@ ProcessingChain.prototype.runChain = function( req, res, finalFn, handler ) {
}
}
if(handler) {
var firstItem = self.findFirstValidItem(handler.name)
var firstItem = self.findFirstValidItem(handler.name, chain)
firstItem.fn(req, res, next)
} else {
this.chain[0].fn(req, res, next )
chain[0].fn(req, res, next )
}
};

ProcessingChain.prototype.findFirstValidItem = function(name) {
if(!name) return this.chain[0]
return _.find(this.chain, function(item) {
ProcessingChain.prototype.findFirstValidItem = function(name, chain) {
if(!name) return chain[0]
return _.find(chain, function(item) {
if(item.names && Array.isArray(item.names) && item.names.length > 0) {
return item.names.indexOf(name) != -1
} else {
Expand Down
62 changes: 42 additions & 20 deletions lib/vatican.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ var http = require("http"),
handlerParser = require("./handlerParser"),
processingChain = require("./processingChain"),
mongoose = require("mongoose"),
_ = require("lodash");
_ = require("lodash"),
path = require("path");


module.exports = Vatican;
Expand Down Expand Up @@ -37,27 +38,27 @@ function Vatican(options) {
this.parseHandlers();
this.paths = [];
this.server = null;
this.totalPreprocessors = 0;
this.preprocessors = new processingChain();
this.postprocessors = new processingChain();
}

Vatican.prototype.preprocess = function(fn, endpointNames) {
this.preprocessors.add({fn: fn, names: endpointNames ? endpointNames : []})
this.totalPreprocessors = this.preprocessors.getTotal();
this.preprocessors.add({fn: fn, names: endpointNames})
}

Vatican.prototype.postprocess = function(fn, endpointNames) {
this.postprocessors.add({fn: fn, names: endpointNames ? endpointNames : []});
this.postprocessors.add({fn: fn, names: endpointNames});
}

Vatican.prototype.parseHandlers = function() {
var dir = this.options.handlers;
Vatican.prototype.parseHandlers = function(cb) {
var dir = path.isAbsolute(this.options.handlers) ? this.options.handlers : process.cwd() + "/" + this.options.handlers;
var self = this;
handlerParser.parse(dir, function(err, path) {
if(typeof cb == 'function' && err) return cb(err)
if(!err) {
self.paths = path;
}
if(typeof cb == 'function') cb(self.paths)
})
};

Expand Down Expand Up @@ -87,13 +88,15 @@ Vatican.prototype.parseRequest = function( req, template, originalReq , cb) {
Vatican.prototype.findMethod = function( url, method ) {
var path = (url.indexOf("?") == -1) ? url : url.split("?")[0];
var nmbrOfParts = path.split("/").length;
var nmbrOfPartsPath = null,
regExpStr = null,
regExp = null

var match = _.find(this.paths, function(item) {
var regExpStr = item.url.replace(/:.+(\/)?/g,".+$1");
var nmbrOfPartsPath = item.url.split("/").length;
//logger.info("Trying to match: [" + item.method + "] " + regExpStr + " with: [" + method + "] " + path);
var regExp = new RegExp(regExpStr + "$");
return regExp.test(path) && (item.method.toLowerCase() === method.toLowerCase()) && nmbrOfPartsPath == nmbrOfParts;
regExpStr = item.url.replace(/\:.+(\/)?/g,".+$1");
nmbrOfPartsPath = item.url.split("/").length;
regExp = new RegExp(regExpStr + "$");
return nmbrOfPartsPath == nmbrOfParts && (item.method.toLowerCase() === method.toLowerCase()) && regExp.test(path);
});
return match;
};
Expand Down Expand Up @@ -144,18 +147,20 @@ Vatican.prototype.requestHandler = function (req, res) {
} else {
try {
var request = this.createRequest(req);
var hdlr = this.loadHandler(process.cwd() + "/" + methodFound.handlerPath);
var hdlr = this.loadHandler(methodFound.handlerPath);
res = vaticanResp.improveResponse(res, request, this.options, this.postprocessors);
//Parse the request to grab the parameters
this.parseRequest(request, methodFound.url, req, function(newRequest) {
//Run the pre-process chain and finally, call the handler
if(self.preprocessors.getTotal() > self.totalPreprocessors) {
self.preprocessors.pop();
}
var hdlrInstance = new hdlr(self.getCorrectModel(methodFound))

hdlrInstance.models = self.dbmodels //Let the handler access all other models in case they're neeeded
self.preprocessors.add({fn: hdlrInstance[methodFound.action].bind(hdlrInstance)})
self.preprocessors.runChain(newRequest, res, null, methodFound);

self.preprocessors.runChain({
req: newRequest,
res: res,
handler: methodFound,
endPrep: hdlrInstance[methodFound.action].bind(hdlrInstance),
});
});
} catch (ex) {
logger.error("Error instantiating handler: " + ex.message);
Expand All @@ -167,7 +172,7 @@ Vatican.prototype.requestHandler = function (req, res) {

Vatican.prototype.getCorrectModel = function(handler) {
var modelName = handler.handlerName.replace("Hdlr", '')
return this.dbmodels[modelName]
return this.dbmodels && this.dbmodels[modelName]
}

/**
Expand All @@ -177,6 +182,7 @@ Vatican.prototype.start = function(cb) {
try {
this.server = http.createServer(this.requestHandler.bind(this));
this.server.listen(this.options.port);
console.log(this.server);
logger.info("Server started on port: " + this.options.port);
if(typeof cb == 'function') {
cb();
Expand All @@ -187,6 +193,22 @@ Vatican.prototype.start = function(cb) {
}
};

/**
Close the server
*/
Vatican.prototype.close = function(cb) {
try {
this.server.close();
logger.info("Server closed");
if(typeof cb == 'function') {
cb();
}
} catch (ex) {
logger.error("Error closing server: " + ex.message);
return false;
}
}

Vatican.prototype.dbStart = function(opts, cb) {
if(typeof opts === 'function') {
cb = opts
Expand Down
40 changes: 22 additions & 18 deletions lib/vaticanResponse.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,30 @@ VaticanResponse.prototype.send = function(txt) {
var headers = {};
var self = this;
this.body = txt;
this.ppChain.runChain(this.request, this, function(req, resp) {
//Check for CORS config
if(self.options.cors !== false) {
headers = _getCORSHeaders(self.options.cors);
}
this.ppChain.runChain({
req: this.request,
res: this,
finalFn: function(req, resp) {
//Check for CORS config
if(self.options.cors !== false) {
headers = _getCORSHeaders(self.options.cors);
}

//Adds the rest of the headers
for(var i in resp.headers) {
headers = _.assign(headers, resp.headers[i]);
}
//Adds the rest of the headers
for(var i in resp.headers) {
headers = _.assign(headers, resp.headers[i]);
}

//Write the headers
resp.response.writeHead(resp.statusCode, headers);
if( typeof resp.body == 'object') {
resp.body = JSON.stringify(resp.body);
}
//Write the headers
resp.response.writeHead(resp.statusCode, headers);
if( typeof resp.body == 'object') {
resp.body = JSON.stringify(resp.body);
}

//Write out the response text
resp.response.write(resp.body);
resp.response.end();
//Write out the response text
resp.response.write(resp.body);
resp.response.end();
},
})

};
Expand Down Expand Up @@ -95,4 +99,4 @@ function _getCORSHeaders(corsOpts) {
module.exports = {
improveResponse: _improveResponse,
writeNotFound: _writeNotFound
};
};
14 changes: 12 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,24 @@
"type": "git",
"url": "https://github.com/deleteman/vatican"
},
"scripts": {
"test": "istanbul cover node_modules/.bin/_mocha -- -u exports -R spec test/*.js"
},
"bin": {
"vatican": "./bin/vatican"
},
"version": "1.2.4",
"version": "1.3.0",
"dependencies": {
"winston": "0.7.3",
"lodash": "2.4.1",
"colors": "0.6.2",
"mongoose": "*"
"mongoose": "*",
"strip-json-comments": "1.0.1"
},
"devDependencies": {
"should": "4.0.4",
"mocha": "1.21.4",
"supertest": "0.13.0",
"istanbul": "0.3.0"
}
}
Loading