node.js
, the name of which will be Spirit.init
we create a daemon, and then with the help of monit
check whether the server has crashed. This topic has long been painted, information can be found in Google , for example on the site nodejs.ru . This approach was tested and approved by me personally using the example of the abbreviation of references to node.js , which in a few hours reduced more than 15,000 references and did not even flinch, it still stands (almost 20 days). server { listen 80; server_name spirit.example.com; access_log /home/spirit/example-app/logs/nginx.access.log; location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://127.0.0.1:8124/; } location ~* \.(html|js|ico|gif|jpg|png|css|doc|xml|rar|zip|swf|avi|mpg|flv|mpeg|wmv|ogv|oga|ogg)$ { root /home/spirit/example-app/public; } }
/home/spirit/
β lib/
β β mysql-libmysqlclient/
β β spirit/
β β MooTools.js
β example-app/
β β engine/
β β β classes/
β β β init.js
β β logs/
β β public/
β another-example-app/
β engine/
β β classes/
β β init.js
β logs/
β public/
lib
directory, we will drop all the libraries we need.lib/MooTools.js
file , which will allow passing methods of objects as arguments without losing context and slightly expanded the prototype string by adding the htmlEscape
, ucfirst
and lcfirst
.require( 'fs' )
. Thus, we include one of the libraries wired into the kernel and described in the documentation .require( './classes/foo' )
or require( '../lib/mootools.js' )
require( '/home/spirit/lib/mootools' )
// __dirname - , // , var libPath = __dirname + '/../../lib'; // : /home/spirit/lib // // fs.realpathSync(libPath), // MooTools , // require(libPath + '/MooTools').apply(GLOBAL); // var spirit = require(libPath + '/spirit/spirit') .createSpirit(__dirname, libPath); // - // , require('http').listen spirit.listen("127.0.0.1:8124");
var foo = new (require( './bar' ). bar );
, in the bar.js
file bar.js
we have to do this: exports . bar = new Class({ /* ... */ });
. First of all, I prefer to declare such variables not in a dot, but in square brackets, then in editors it is highlighted as a string (of which there is usually the least), which additionally highlights the name of the class with which we work. Secondly, at first I didnβt like this approach and I even found it inconvenient (in the example above, there is a need to require
repeat the bar
twice), but in the end we will turn it so that it plays into our hands - it will be comfortable and beautiful. So, the function to create the main framework class: exports['createSpirit'] = function (projectPath, libPath) { return new Spirit(projectPath, libPath); };
app/classes
and lib/spirit/classes
pastebin.com/0b14MEbe
var Spirit = new Class({ Binds: ['hit', 'load'], initialize : function (String projectPath, String libPath) { }, load : function (String className, Boolean fromSpirit) { // load , : // spirit.load('Controllers.User'); // , , - // fromSpirit // , }, loadLib : function (libName) { // , : // spirit.loadLib('mysql-libmysqlclient') // libPath // }, // hit : function (req, res) { }, listen : function (port, url) { // // .listen(8124, '127.0.0.1') // .listen('127.0.0.1:8124') } }); var load = function (path, className) { // some code is here // // Spirit. ? // ! return data[className](this); };
exports['Name.Space.ClassName'] = function (spirit) { return new Class({ method : function (msg) { this.response.writeHead(200, {'Content-Type': 'text/plain'}); this.response.end(msg); } }); };
exports['Helper.AnotherClass'] = function (spirit) { var mysql = spirit.loadLib('mysql-libmysqlclient'); return new Class({ Extends : spirit.load('Name.Space.ClassName'), start : function (msg) { this.method('Started'); }, query : function () { // using mysql } }); };
Name.Space.ClassName
? require( '../Name/Space/ClassName' );
? And if the class to move to another place - would rewrite all the way? Would a library be loaded by writing the full path? exports['Router'] = function (spirit) { return new Class({ // .. hit : function (request, response) { // some code }, // .. }); };
exports['Router'] = function (spirit) { var Logger = spirit.load('Logger'); var logger = new Logger; return new Class({ Extends : spirit.load('Router', true), hit : function (request, response) { logger.log('hit!'); this.parent(request, response); }, // .. }); };
/home/spirit/example-app/
β engine/
β β classes/
β β β controllers/
β β β β Admin/
β β β β β Articles.js
β β β β β Index.js
β β β β Man/
β β β β β Index.js
β β β β β Route.js
β β β β Index.js
β β β β Users.js
β β β Controller.js
β β init.js
β logs/
β public/
</test-:A>
does not match the URL " /test-abc123
", while the expression /test-:A
matches this URL. All templates are added to an array and passed as an argument when calling the controller method. If there is an argsMap, then the Hash is passed. For example, at the address " /articles-15/page-3
" the first argument will be an array [15, 3]
, but if you pass argsMap : ['id', 'page']
, the hash will be passed to the method {id:15, page:3}
. spirit.createRouter() .addRoutes( { route : "</article-:D/page-:D" , contr : 'Man.Route:articleWithPage' , argsMap : ['id', 'page'] }, { route : "</article-:D" , contr : 'Man.Route:article' , argsMap : ['id'] }, { route : "</~:W>" , contr : 'Man.Route:user' }, { route : "</hash-:H>" , contr : 'Man.Route:hash' } );
exports['Controllers.Man.Route'] = function (spirit) { return new Class({ Extends : spirit.load('Controller'), indexAction : function () { this.exit('(Man.Route) index action'); }, testAction : function () { this.exit('(Man.Route) test action'); }, articleWithPageAction : function (args) { this.exit('(Man.Route) article #' + args.id + ', page #' + args.page); }, articleAction : function (args) { this.exit('(Man.Route) article #' + args.id); }, hashAction : function (args) { this.exit('(Man.Route) hash: ' + args[0]); }, userAction : function (args) { this.exit('(Man.Route) user: ' + args[0]); } }); };
exit
method: exports['Controller'] = function (spirit) { return new Class({ exit : function (msg) { this.response.writeHead(200, {'Content-Type': 'text/plain'}); this.response.end(msg); } }); };
createRouter : function () { var Router = this.load('Router'); var router = new Router(); router.spirit = this; this.router = router; router.init(); return router; }, hit : function (req, res) { this.router.hit(req, res); },
exports['Router'] = function (spirit) { var RouterHelper = spirit.load('Router.Helper'); return new Class({ init : function () { var path = this.spirit.requirePath + 'Controllers'; this.routerHelper = new RouterHelper(this); this.routerHelper.requireAll(path); }, hit : function (request, response) { var contrData = this.routerHelper.route(request); var contr = contrData.contr; contr.spirit = this.spirit; contr.request = request; contr.response = response; if (typeof contr.before == 'function') contr.before(); contr[contrData.method](contrData.args); if (typeof contr.after == 'function') contr.after(); }, addRoutes : function () { var rh = this.routerHelper; rh.addRoutes.apply(rh, arguments); } }); };
var fs = require('fs'); exports['Router.Helper'] = function (spirit) { var RouterPlain = spirit.load('Router.Plain'); var RouterRegexp = spirit.load('Router.Regexp'); return new Class({ initialize : function (router) { this.router = router; this.plain = new RouterPlain(this); this.regexp = new RouterRegexp(this); }, route : function (request) { var url = request.url; return this.regexp.route(url) || this.plain.route(url); }, requireAll : function (path) { var files = fs.readdirSync(path); for (var i = 0; i < files.length; i++) { var file = path + '/' + files[i]; var stat = fs.statSync(file); if (stat.isFile()) { this.addController(file); } else if (stat.isDirectory()) { this.requireAll(file); } } this.checkAllIndexActions(); }, // regexp addRoutes : function (routes) {}, // ".js" removeExt : function (file) {}, // indexAction checkAllIndexActions : function () {}, // addController : function (file) {}, // false, createController : function (name) {} }); };
addRoutes
exports['Router.Regexp'] = function (spirit) { return new Class({ initialize : function (routerHelper) { this.routerHelper = routerHelper; }, route : function (url) { // for (var i = 0; i < this.routes.length; i++) { var route = this.routes[i]; // // lastIndex, // , // route.regexp.lastIndex = 0; var result = route.regexp.exec(url); if (result) { return { contr : this.routerHelper .createController(route.contr.name), method : route.contr.method, args : this.regexpRouteArgs(result, route.argsMap) }; } } return false; }, routes : [], addRoute : function (route, controller, argsMap) { }, addRoutes : function (hash) { }, // , addRoutes // , // ( )) - regexpContr : function (string) { var parts = string.split(':'); var method = parts.length > 0 ? parts[1] + 'Action' : 'indexAction'; var contr = 'Controllers.' + parts[0]; // ... }, // // // , regexpRoute : function (route) { var re = new RegExp(); re.compile(this.prepareRegexp(route), 'ig'); return re; }, replaces : { A : '([az]+)', D : '([0-9]+)', H : '([0-9a-f]+)', W : '([0-9a-z]+)', }, prepareRegexp : function (route) { return route .escapeRegExp() .replace(/>$/, '$') .replace(/^</, '^') .replace(/:([ADHW])/g, function ($0, $1) { return this.replaces[$1]; }.bind(this)); }, // , regexp.exec // input lastIndex // , argsMap regexpRouteArgs : function (result, argsMap) { }, }); };
var url = require('url'); exports['Router.Plain'] = function (spirit) { return new Class({ initialize : function (routerHelper) { this.routerHelper = routerHelper; }, route : function (url) { var parts = this.getControllerName(url); var controller = this.routerHelper.createController(parts.name); var method = 'indexAction'; if (parts.args.length) { var action = parts.args[0].lcfirst(); // - // - , - indexAction if (typeof controller[action + 'Action'] == 'function') { method = action + 'Action'; parts.args.shift(); } } return { contr : controller, method : method, args : parts.args }; }, getControllerName : function (url) { var controllers = this.routerHelper.controllers; // pathname var path = this.splitUrl(url); var name, args = []; do { if (!path.length) { // - name = 'Controllers.Index'; break; } // name = 'Controllers.' + path.join('.') + '.Index'; if (controllers[name]) break; // - name = 'Controllers.' + path.join('.'); if (controllers[name]) break; // - args.unshift(path.pop()); } while (true); return { name : name, args : args }; }, splitUrl : function (urlForSplit) { return url .parse(urlForSplit, true) .pathname.split('/') .filter(function (item) { return !!item; }) .map(function (item) { return item.ucfirst(); }); }, }); };
shock/spirit/init.js/f81e45
". I suggest using this link template:http://example.com/compare/( shock/spirit/init.js/f81e45 )/( tenshi/spirit/src/init.js/d5d218 )
, in which each file is shown in brackets. But the framework tools do not allow this. No problem. In our project (without touching the framework) we create the class Router.Regexp: exports['Router.Regexp'] = function (spirit) { return new Class({ Extends : spirit.load('Router.Regexp', true), prepareRegexp : function (route) { return this.parent(route) .replace(/:P/g, '([0-9a-z._\\/-]+)'); } }); };
spirit.createRouter() .addRoutes( // ... { route : "</compare/(:P)/(:P)>" , contr : 'Man.Route:compare' } );
compareAction : function (args) { this.exit('Compare "' + args[0] + '" and "' + args[1] + '"'); }
http://example.com/compare/( shock/spirit/init.js/f81e45 )/( tenshi/spirit/src/init.js/d5d218 )
and get the answer:Compare " shock/spirit/init.js/f81e45 " and " tenshi/spirit/src/init.js/d5d218 "
Source: https://habr.com/ru/post/106846/
All Articles