Dynamic applications with Ocsigen or Yoba returns
What does a normal person do on a cold Sunday morning? Anyone will answer you: on a cold Sunday morning, a person is sleeping. Because he worked all week and wants to relax.
What does a programmer do on a cold Sunday morning? On a cold Sunday morning, the programmer drinks hot tea and writes the code. He drinks tea because the morning is cold, and he has not woken up yet, and he writes the code because he wants to. A programmer always wants to write a code, only on weekdays he writes a code for money and is very tired of this, and on weekends for himself, so he rests.
This morning we will be writing our first application for Ocsigen. It would be nice for those who wish to first familiarize themselves with the official manualhowever, one should not hope for much, because the manual is unfinished, replete with perplexing lines a la "??????" and foul language in French. Therefore, I will be the main manual.
As you may remember, we once wrote the interpreter of the Yoba language. Since then, the interpreter has been slightly improved, allocated to a separate class, began to take a line to the input, give the line to the output (instead of working with the console). Now our task will be tointroduce Yoba as the main language of Google, turning the Yoba interpreter into a web application, and not just a simple one, but a client one. Although I added an operation counter to the class so that I couldn’t become too impudent, but still - let the user spend on his computer computing power, and not on the server.
First, we need to install the ocsigen server. Since we have not yet managed to compile 2.0 for distributions, we will follow this instruction and install the bundle server in our home directory. In order for the bundle to turn out to be correct and tasty, before running make, edit Makefile.config and write it there: we will not collect Ocaml and Findlib, they are already in the repositories. This time we won’t need O'Closure, but we’ll collect it just in case — so that we don’t have to reassemble oxygen later, if you yourself are interested in it or want an article from me.
The next item will immediately edit the file $ {HOME} /bin/ocsigen/etc/ocsigenserver/ocsigenserver.conf: make sure that the appropriate port is written there, as well as the name and group of the user to start from. Now it's time to prepare the config for the future site. Create $ {HOME} /bin/ocsigen/etc/ocsigenserver/conf.d/yoba.conf and fill it with the contents:
Briefly about the content:
Hurrah! We turn to writing code.
We create the notorious folder / home / username / yoba / and download the archive with the Yoba language - we already wrote the language itself, but it’s not interesting for us to file it a bit and turn it into a class, so we’ll take it right away. We unpack it into the same folder and download the standard Makefile.config and Makefile.rules to the same place - building a project is not easy, you can write a fig file from scratch.
The time has come to fix something and immediately learn about the first syntax innovations: in Eliom code can be placed in sections. Section {server {...}} (the same as code without a section) is compiled and executed on the server, section {client {...}} - on the client, and{shared {...}} - available both there and there.
Since our interpreter will work on the client, we rename the yobaLang.ml file to yobaLang.eliom, open it, and at the very beginning add the line "{client {", and at the very end replace ";;" (two semicolons - this is the end of the instruction only at the top level of the code, they can no longer be used inside the section) to "}}". The generated ocamllex and ocamlyacc code will be similarly edited in the makefile when we write it.
In the meantime, let's write a file that will do everything. Call it, say, home.eliom.
At the beginning of the file, open the modules for the future and immediately create a line with sample code that will be offered to the visitor.
Next, we will create a module of our application - in order for the client-server interaction to work correctly, all services are registered on behalf of an application. Fortunately, this is easy:
Add a function that will execute the code on Yobe and return the result, the function will be purely client, the server will not even know about it
Create a service that will process user requests. Creating services in ocsigen is unusually simple and convenient, each service is characterized by a way and a set of strongly typed (!) GET / POST parameters. Accordingly, the server decides which service to process the request, based on the request. You can create a default service that will process requests without parameters, a second service at the same address that will process requests with one GET parameter, and a third service with one POST parameter. And they will not be confused. But for now, we only need one service:
The path symbolizes that the service will be given along the default path for the site (as an index page in Apache), and in ~ get_params we indicated that the service does not accept parameters.
It's time to write a page template:
As you can see, all page elements are functions that take strictly defined parameters as input, due to which the static typing of the created HTML page is carried out. So, the html function accepts two parameters as an input - one of type `Head, and the second of type` Body. And div - takes as input a list of elements allowed to be inside the div.
But we will dwell in more detail on the other. Firstly, our page_template function accepts two parameters as input - a code and a visitor counter. The first is placed in textarea, and the second is inside the tag
What does a programmer do on a cold Sunday morning? On a cold Sunday morning, the programmer drinks hot tea and writes the code. He drinks tea because the morning is cold, and he has not woken up yet, and he writes the code because he wants to. A programmer always wants to write a code, only on weekdays he writes a code for money and is very tired of this, and on weekends for himself, so he rests.
This morning we will be writing our first application for Ocsigen. It would be nice for those who wish to first familiarize themselves with the official manualhowever, one should not hope for much, because the manual is unfinished, replete with perplexing lines a la "??????" and foul language in French. Therefore, I will be the main manual.
As you may remember, we once wrote the interpreter of the Yoba language. Since then, the interpreter has been slightly improved, allocated to a separate class, began to take a line to the input, give the line to the output (instead of working with the console). Now our task will be to
First, we need to install the ocsigen server. Since we have not yet managed to compile 2.0 for distributions, we will follow this instruction and install the bundle server in our home directory. In order for the bundle to turn out to be correct and tasty, before running make, edit Makefile.config and write it there: we will not collect Ocaml and Findlib, they are already in the repositories. This time we won’t need O'Closure, but we’ll collect it just in case — so that we don’t have to reassemble oxygen later, if you yourself are interested in it or want an article from me.
LOCAL := ${HOME}/bin/ocsigen
DEV := YES
OCAMLDUCE := YES
OCLOSURE := YES
OTHERS := YES
The next item will immediately edit the file $ {HOME} /bin/ocsigen/etc/ocsigenserver/ocsigenserver.conf: make sure that the appropriate port is written there, as well as the name and group of the user to start from. Now it's time to prepare the config for the future site. Create $ {HOME} /bin/ocsigen/etc/ocsigenserver/conf.d/yoba.conf and fill it with the contents:
utf-8 10000 application/x-javascript
Briefly about the content:
- staticmod allows the server to return static data (in our case, this will be a compiled .js file
- ocsipersist-sqlite - allows us to work with persistent data, then we'll see why this is necessary
- deflatemod, as expected, presses the data when it is sent. Below you can see the deflate section in the site settings, which says that we only press js. Note: you cannot choose the compression method - gzip or deflate - it is automatically selected based on client expectations.
- eliom.server provides the entire server part of the framework
- In the hostfilter parameter of our host, we say that we respond to all domains
- And indicating an empty path for the site, we say that the site is located in the root of the domain. Replacing the empty line with, say, “yoba”, we will force our site along with all the static content to be given to the address hostname / yoba - an unambiguous profit, you can keep several sites on the same domain and shuffle them as you like
- / home / username / yoba will be our directory with the code (and the compiled yoba.js file), and in _build / server will be the compiled server module. Of course, ideally, you need to compile, then transfer the code to a separate folder, and still do not store static content in the same folder with the compiled module, but now we will do so to quickly check the code
Hurrah! We turn to writing code.
We create the notorious folder / home / username / yoba / and download the archive with the Yoba language - we already wrote the language itself, but it’s not interesting for us to file it a bit and turn it into a class, so we’ll take it right away. We unpack it into the same folder and download the standard Makefile.config and Makefile.rules to the same place - building a project is not easy, you can write a fig file from scratch.
The time has come to fix something and immediately learn about the first syntax innovations: in Eliom code can be placed in sections. Section {server {...}} (the same as code without a section) is compiled and executed on the server, section {client {...}} - on the client, and{shared {...}} - available both there and there.
Since our interpreter will work on the client, we rename the yobaLang.ml file to yobaLang.eliom, open it, and at the very beginning add the line "{client {", and at the very end replace ";;" (two semicolons - this is the end of the instruction only at the top level of the code, they can no longer be used inside the section) to "}}". The generated ocamllex and ocamlyacc code will be similarly edited in the makefile when we write it.
In the meantime, let's write a file that will do everything. Call it, say, home.eliom.
At the beginning of the file, open the modules for the future and immediately create a line with sample code that will be offered to the visitor.
{shared{
open Eliom_pervasives
open Lwt
open HTML5.M
open Eliom_parameters
open Eliom_request_info
open Eliom_output.Html5
open Ocsigen_extensions
let code_example = ref "
чо люблю сэмки йоба
чо люблю пиво йоба
чо люблю яга йоба
чо люблю итерации йоба
чо пиво это 1 йоба
чо яга это 2 йоба
усеки результат это
чо покажь итерации йоба
чо покажь сэмки йоба
йоба
усеки фибоначчи это
чо сэмки это пиво и яга йоба
чо пиво это яга йоба
чо яга это сэмки йоба
чо итерации это итерации и 1 йоба
чо есть итерации 50 тада хуйни результат или хуйни фибоначчи йоба
йоба
чо хуйни фибоначчи йоба"
}}
Next, we will create a module of our application - in order for the client-server interaction to work correctly, all services are registered on behalf of an application. Fortunately, this is easy:
module My_appl =
Eliom_output.Eliom_appl (
struct
let application_name = "yoba"
end)
Add a function that will execute the code on Yobe and return the result, the function will be purely client, the server will not even know about it
{client{
let yoba_execute str = (
let yparser = new YobaLang.yoba_interpretator () in
yparser#parse str;
yparser#get_output)
}}
Create a service that will process user requests. Creating services in ocsigen is unusually simple and convenient, each service is characterized by a way and a set of strongly typed (!) GET / POST parameters. Accordingly, the server decides which service to process the request, based on the request. You can create a default service that will process requests without parameters, a second service at the same address that will process requests with one GET parameter, and a third service with one POST parameter. And they will not be confused. But for now, we only need one service:
let empty_service = Eliom_services.service
~path:[""]
~get_params:(Eliom_parameters.unit)
();;
The path symbolizes that the service will be given along the default path for the site (as an index page in Apache), and in ~ get_params we indicated that the service does not accept parameters.
It's time to write a page template:
let page_template code_input counter_value =
html
(head
(title (pcdata "Yoba interpreter")) []
)
(body [
h1 [pcdata "Yoba! For human beings"];
p [pcdata "Вас приветствует Йоба! Йоба — это чотко!"];
div [
raw_textarea ~a:[a_id "clientcode"] ~name:"clientcode" ~rows:25 ~cols:60 ~value:code_input ();
raw_button ~button_type:`Button ~name:"clientbutton" ~a:[a_id "clientbutton"] ~value:"Кликай!" [pcdata "Кликай!"];
];
pre ~a:[a_id "clientoutput"] [];
hr ();
p [pcdata "Йоба-скриптов хуйнули уже: "; b [pcdata (string_of_int counter_value)]]
]);;
As you can see, all page elements are functions that take strictly defined parameters as input, due to which the static typing of the created HTML page is carried out. So, the html function accepts two parameters as an input - one of type `Head, and the second of type` Body. And div - takes as input a list of elements allowed to be inside the div.
But we will dwell in more detail on the other. Firstly, our page_template function accepts two parameters as input - a code and a visitor counter. The first is placed in textarea, and the second is inside the tag
at the bottom. Secondly, the names of the raw_textarea and raw_button functions are so raw - for good reason. There are similar simple non- “raw_” functions, but they are designed to create elements inside wonderful, strongly typed forms that always refer to some service (in other words, when creating a form, we immediately verify that it will send the strictly required list to where parameters). And our textarea and button (this is not a tag, and the most natural tag