Better a little fish than a big cockroach.Russian proverb

Lua likes everyone, it is simple, but not primitive. No, rather - thoughtful, verified, optimal. R.Ieruzalimsky (author of the language), in his book “Programming in the Lua language” writes: “Lua is a tiny and simple language”. This is true. And it is also scriptable, portable, efficient, extensible, gluing (glue). How can you not try this?
Like many others, I was tempted to look into what Lua is all about. Well, since the best way to learn a language is to write a program on it, I decided to jot down a simple web microform for Apache server (version 2.3+). Apache is selected because it is on every hosting, and all configuration under Lua is to enable the mod_lua.so module in the server configuration. Of course, this solution will be slower than on Nginx, but maybe we don’t need more?
I enjoyed reading the April Fool's article
in nginx: inline php noodle codes about creating a Lua site for Nginx in the style of early PHP. As you know, in every joke ... I did not reach the first of April, but Friday is not bad either. At least two unambiguous conclusions can be made from the written article: on Lua, you can develop websites (or engines for them), websites will definitely be fast.
Starting to write the framework, which is micro, I was not sure that it would work in principle at all. It was interesting and curious, especially since the Lua language was not familiar to me. I had to learn the language and on the go figure out how to use it. The result obtained in a couple of weeks does not claim to be great and great (and is not intended for use in production), but I still hope that I can make a small contribution to the popularization of Lua in the web programming environment.
')
Framework architecture

Although the word architecture is too loud, nevertheless, the framework has a structure, and I will try to describe it. With the start, initialization occurs and DI starts. With it, Front is launched - the main controller. Front receives a request from Request, sends it to Router and receives the name of the controller. The controller has several presenters (for example, an article presenter, a menu, etc.). Having collected the answers of the presenters, the controller returns the answer to Front, and he sends the answer to the output. Everything is quite simple and transparent.
Front is the most important, but he himself does nothing (the work is done by presenters). The controller (one of them) is responsible for what presenters will be on the user's page. The presenter must fulfill his mission and give an answer containing the name, description and content (you can also fasten the date to give Last-Modified, as I did at least in PHP). What of the presenter’s response to use, and what’s not, is decided by the controller. Templating is implemented natively, so on the one hand it is fast, on the other hand, it requires development (the package / Demo / View directory / is empty for now)
Details
Having set up the htaccess file so that all requests go to index.lua, in the index file we have to create the function handle (r), which takes the request_rec table as an argument, the structure of its contents can be found here:
httpd.apache.org/docs/trunk/ mod / mod_lua.html After receiving the request, you can continue to write code to process it. (In the router, by the way, on POST requests and on GET requests that did not fall into any route, there are still stubs.)
It seemed to me interesting to use Lua's capabilities for creating and using precompiled code. This approach has an obvious advantage in improving performance, because the precompilation phase is skipped every time the program is started. Well, the disadvantage is that you can’t directly edit the precompiled file - you need to edit the source code and compile the file again. The program can be made to compare the date of the last file change each time, but for a “fast” site this is not quite the right decision. I still do not consider the option of using memkesh, I will leave it for the future.
For convenience, and probably out of habit, I organized the code in pseudo-OOP style. Encapsulation is implemented, probably because I value it most of all (subjectively). Polyformism was not required, and I will do the inheritance when it is necessary. Of course, for a small framework written to create small sites, it would be possible to get away with functions at all, but this is somehow inconvenient, although it is quite possible.
Class naming in the framework is classically done: it conveys the physical location of the file. For example, the CoreKernelRoute class indicates that the Route.lua file is located in the Kernel subdirectory of the Core package. Full path from the root of the package / Core / Kernel / Route.lua site. Thus, a simple (yes, everything is simple and small) dependency detector easily collects all dependent classes for the created object and passes them to it in the constructor. The list of dependencies is stored in the system / dependency.lua file. If you want the object to be a singleton, then you need to register it with the system / single.lua file.
Demo
So that familiarity with the framework does not mean a simple reading of the article with not very clear explanations of the author, I added a primitive Demo module in the framework, by which you can understand and see (if you place the distribution on the server) the work of the site. All controllers are in the package / Core / Controller / directory. All of them, except Hello.lua, use the DemoPresenterArticle presenter to generate a list of articles from the DemoDataDb demonstration base, and the Page controller also receives the content of a specific article from this presenter.
Hello.lua controller - made exactly as Hello world! - this is the shortest path that the script can do, while fully utilizing its core (if you test for maximum speed, then this is exactly this page). By the way, for the main page to work correctly, do not forget to add index.lua in httpd.conf in the DirectoryIndex section.
Example
Let's say you want to show time on the main page. To do this, you need to create a presenter DemoPresenterTime with a pair of methods that return time on the server in 24-hour or 12-hour format. You can add a method that returns a date (the name of the presenter is completely implied). It should be located at package / Demo / Presenter / Time.lua
DemoPresenterTime function genObj() local M = {} local L = {} function M.doJob(route, event) event = event or 'Clock24' local exe_event = 'exe' .. event if L[exe_event] then local id_page = tostring(route.id_page) return L[exe_event](id_page) else return L.conf.Core.array_error_1 end end
Now we save the template CoreTemplatePage as CoreTemplateIndex - we make an individual template for the main page. Add {server_time} somewhere under the menu. If you add {server_time} to CoreTemplatePage, then you will need to connect the presenter to each controller, but in our plans it is not.
In the controller CoreControllerIndex add after the block with the sidebar
And in the file system / dependency.lua for this controller we connect a new presenter with the line
server_time = 'DemoPresenterTime',
Everything, the presenter has been created, and you can watch the server time on the main page, which is quite “interesting” for a visitor, especially if your hosting is somewhere on the other side of the planet :)
Style
I am afraid that my previous “experience” of writing scripts on PHP influenced the architecture and the design style of the framework too much. I do not undertake to write it down in the "best practice". But I liked writing on Lua. The code is concise, the number of parentheses is small, the semicolons are not needed at the end of lines. It also seemed to me very convenient to use multi-line comments - [[-]], it is enough to put any character between pairs of brackets and the code block came out of comments, deleted - everything is back in the comments.
Functions classes return objects that are essentially closures. It turned out to be very easy to think with such closures, although I had previously avoided this practice. But I suppose, I still have a deep perception of Lua ahead of me, and maybe waiting along with the Cortutins and the C API. In general, Lua somehow everything in its place, which leaves a clear sense of the thoughtfulness of the language, without screwing the details forgotten in a hurry (especially IMHO, without holivarnosti).
Lua and PHP
This paragraph is not for the sake of fuel injection into the fire of holy wars. I just wrote a little PHP and can draw some kind of parallel. Although I liked Lua, it does not mean that it is better than PHP. Maybe I just want something new. In addition, when working with PHP, a habit has arisen for the most detailed high-quality documentation, a huge number of examples, articles, chewing on a variety of trifles, licked libraries and modules that have innumerable numbers, and which are either already at the actual hosting or they will be connected to of necessity.
If someone had asked me what to write on a large and complex project, I would say that I like Lua, but better write in PHP. Nevertheless, I believe that Lua should occupy at least a small, but rather significant niche in web building. He is fast, easy and simple, and if this is all that is needed, then why not? In addition, thanks to the initial design of the language for integration with C, the solution based on Lua (and LuaJIT) is well shown the road to the highway. By the way, it was very interesting to me to read about the possibility of writing
applications on Lua in Tarantool .
Spherical horse
It is better to consider any independent benches relatively, since the setting of the operating system, iron, can greatly affect the results. Anyway, you should be able to test too. But in comparison a lot of things become clear, in every case in the categories “faster-slower”, i.e. subjective.
On my old XXX comp indicators:
home page (2 presenters)
- ab -n 1000 -c 10 -> 622 r / s
- ab -n 1000 -c 100 -> 582 r / s
article3.html (2 presenters)
- ab -n 1000 -c 10 -> 660 r / s
- ab -n 1000 -c 100 -> 634 r / s
Hello world! (no presenter, only controller)
- ab -n 1000 -c 10 -> 736 r / s
- ab -n 1000 -c 100 -> 727 r / s
For comparison
the speed of the simple r: puts ("Hello World !!!"), on Lua without a framework
- ab -n 1000 -c 10 -> 2210 r / s
- ab -n 1000 -c 100 -> 2067 r / s
The main page of the site, made in PHP framework, similar to the applied architectural principles, but a little more complex (with some kind of templating system, etc.) and with four static presenters (i.e., the presenter loads static content - text) despite similarity of the implementation of the numbers please watch only the corner of my eye
- ab -n 1000 -c 10 -> 207 r / s
- ab -n 1000 -c 100 -> 187 r / s
The general conclusion from superficial testing is as follows: the framework for initializing the kernel spends on the order of a millisecond, which is naturally not small, but for a regular site this value is very small. It also spends a bit of memory: without the 25Kb framework, with the 61Kb framework, a total of 36Kb (with the growth of the framework, the figure will certainly grow). Considering that the framework collects about a dozen different files, I think the result can be called acceptable.
Precompilation efficiency
By generating precompiled .ls files, I was able to see how effective this solution was. I came to the conclusion that the effect grows on large files. Those. if the code of the framework were compiled in one file, it would greatly affect the speed of work. Precompiling the same small effect files does not. In the Demo package, a simple lua table is used as the database. Having increased it to a megabyte, I saw a very strong effect of using a file in a precompiled form on the speed (I don’t want to bring another spherical horse here, but the difference was an order of magnitude). I would say that for a small site (in the sense of database size), it is quite possible to manage storing data in a lua-table, without using SQL, this is certainly not a panacea, but quite a stand-by decision.
GutHub Link:
github.com/claygod/Rumba