
If you are programming on
node.js , but are tired of writing routing requests in code, you do not have a prejudice against using global variables for business purposes and you agree that excessive freedom is destructive for the masses, then the totalitarian weekend group prepared for you a prototype of an alternative platform for
web application development . I warn you that the totalitarian style does not involve embedding the framework into an application through require, but rather embedding your application into the framework structure, where application code fragments will deal with additional restrictions and imposed code and data structures at every step. About the fact that
“less-than-expert” will be able to develop high-performance systems, according to the developers of the node - well, here you yourself understand what these systems will be, especially asynchronous, with lost callbacks and memory leaks at every step. In terms of protection from the fool, this prototype does not deliver miracles. And of course, I expect a lot of constructive criticism from you, because the prototype is crude, although it has gathered a lot of conceptual developments of our team over the past decade. Even the name
Impress appeared just two days ago and, yes, this is the most difficult question.
Features and Features
- URL-based routing based on the file system - created a directory - this is already part of the URL, the directory immediately inherits all handlers from the parent directory, and everything that will be placed in the directory itself will override the execution logic or the appearance of the pages. Since we mainly focus on one-page applications with dynamic interaction with the server, then all this, for the most part, is needed not to generate pages, but to quickly write server API based on JSON. The sequence of request processing, first searches for and executes the file request.js in the requested directory or along the chain of parent directories until it finds or places the application root, then searches for and executes a file with the name corresponding to the HTTP method (get.js, post.js etc.), then it renders the templates.
- Caching server-side JavaScript and in-memory templates — all handlers and templates are first stored in memory, where they are supplied with indices for quick retrieval when reused.
- The ability to change the application code without rebooting the main application - all directories from which files were read are monitored, and when we change the code and templates on the disk, we update the cache, and when we delete files, we clear the cache.
- Servicing multiple ports , network interfaces, hosts, and protocols at once we have a statefull application, i.e. Since we store the state in RAM (user sessions and the state of other domain objects), it is very useful that all server components serving the same user on different ports (for example, HTTP and SSE) have shared shared memory.
- Several launch strategies:
- One process (all served in one processing thread).
- Specialized processes (for each port has its own worker + main master process).
- Multithreaded non-specialized processing (single-type workers, non-specialized processes, the master accepts requests from all ports and distributes them randomly among the workers).
- Multi-threaded processing with client binding by IP addresses to certain workers (sticky by IP) so that subsequent client requests then fall into the particular worker in which his session and other state structures associated with him are already deployed.
- Specialization of processes with isolation by application (not included in the release, tested) - if several applications are running on the same system, and one can interfere with another, then it is better to separate them into different workers.
- Budding of separate processes for processing certain URLs (not included in the release, is being developed) is specifically for processors that assume a long blocking logic, for these cases, the common reactor scheme does not fit, and we give the user a "request is being processed", we rebind the processor. and at the end of processing, it will return the IPC results to the parent worker, which, for example, by SSE will return them to the client.
- Built-in simple template engine with support for include, inheritance and redefinition of template fragments in subdirectories. The template engine has access only to data generated by business logic handlers and placed in res.context. If you ask why I didn’t screw in a ready-made, for example, EJS, then look at their code, in EJS, for example, a bunch of synchronous operations, others have other defects, and we don’t need anything complicated for AJAX applications. On the client, take any template maker - not regulated.
- Cookies support and session mechanism - including the state in memory or the stored state in MongoDB, if the worker crashes, then at the next request the status will be raised from the database, and it is saved only when changes are made. Unidentified session keys are discarded and deleted.
- Returning static content and streaming - there is still a lot of work to be done, static caching will soon appear in memory and control of this cache in the config.
- Built-in query (reverse-proxy) router with url-rewriting support — we can separate URLs, by regular expression, redirect to another host and port, ensuring the response is returned to the user from it.
- Flexible configuration in JSON format with the ability to change without completely restarting the main application (which is now still sometimes crashing).
- Simple query logging - either you need to develop it or screw in a ready-made solution.
- The built-in means of access to the database - as a database, so far only Mongo, but to independently access other databases is not forbidden.
Plans for the near future
- Add support for offline applications (HTML5 Offline Applications Cache) with manifests, etc.
- Implement file download via POST requests.
- Cache statics in RAM with flexible management of this cache from the configuration.
- Fasten an optional geoIP lookout.
- Make custom error page templates (404, etc.).
- Introduce access restrictions to directories through the access.js files placed in them.
- Support for the optional output of the API handlers' results not only in JSON, but also in XML (with my individual intolerance to XML, please consider this heroic step), as well as receiving requests to the API in XML format (hold me seven).
- A simple CMS with content storage in MongoDB.
- Plugin to send email from applications.
- Support for SSE (Server-Sent Events) for broadcasting events from the server to clients initiated by the server (currently in development).
- Demonization and "graceful shutdown" (now in development).
Installation and Setup
1. Install from npm (
https://npmjs.org/package/impress )
$ npm install impress
2. Copy the project template - the contents of the / node_modules / impress / examples / copyContentToProjectFolder directory are transferred to the project directory (server.js, setup.js, config.js and the sites directory).
3. Nasraivaem file config.js go through the sections of the config:
databases - databases that will be automatically opened at startup and the listed collections will be available placed in this way: db.dbName.collectionName.find (...). Configuration example:
dbName: { url: "mongodb://localhost:27017/dbName", collections: ["collname1", "collname2"] }
session - the name of the length and character set to generate a session cookie, the name of the database for permanent storage of sessions.
cluster - setting up an instantiation strategy (multi-threaded type).
servers - named servers (interface / port), for each hosts field - an array of named hosts that need to be sent from this server, static - an array of file masks for static rendering, for example ["/ css / *", "/ images / *" , "/ js / *", "/favicon.ico", "/index.html"].
hosts - named hosts (virtual hosts), you can use masks for naming, for example "* .myhost.com".
routes - Named Request Forwarding Routes.
4. To initialize the data structures in MongoDB, run node setup.js and click “y”.
')
5. In the server.js file, we can also write our own additional code for initialization:
require('impress'); impress.init(function() {
6. And start the server $ node server.js
See examples
1. Templates: when the server is running, open
http: // localhostand look at the template here: /sites/localhost/html.template
We look at the application, click "Create account", "Sign In"
2. Example of redefining the “left.template”
template with logic inheritance, open
http: // localhost / overrideand look at the template here: /sites/localhost/override/left.template
base template here: /sites/localhost/html.template
server logic handler here: /sites/localhost/request.js
3. An example of an API method with a JSON response is:
http: //localhost/api/examples/methodName.jsonand code here /sites/localhost/api/examples/methodName.json/get.js
4. An example of starting an anonymous session :
http: //localhost/api/auth/anonymousSession.jsonand code respectively: /sites/localhost/api/auth/anonymousSession.json/get.js
5. Example of a POST request : with an effort of thought, we do a POST at
localhost / api / auth / regvalidation.json with the “Email” parameter
and code: /sites/localhost/api/auth/regvalidation.json/post.js
6. Example of access to the MongoDB database ::
http: //localhost/api/examples/getUsers.jsonand the code is here: /sites/localhost/api/examples/getUsers.json/get.js
or here it is right:
module.exports = function(req, res, callback) { res.context.data = []; db.impress.users.find({}).toArray(function(err, nodes) { res.context.data = nodes; callback(); }); }
Links
On Github:
https://github.com/tshemsedinov/impressIn npm:
https://npmjs.org/package/impressUPD: Very rough tests on the
Hetzner EX4 hosting
(Intel Core i7-2600 Quad-Core, 16 GB DDR3 RAM) gave 22`572 requests per second with a template of 5 files and a simple request to the database.