Developers Club geek daily blog

1 year, 4 months ago
For the last year on Habré there were several articles about use of a dialplan of lua in asterisk (time, two, three, four). It is rather interesting method of writing of flexible and powerful dialplan. But to try such method of writing of dialplan it is necessary to spend time quantity: to set the necessary libraries, to rebuild with necessary for options an asterisk.

In addition many users have asterisk'the different level of preparation: someone is closer to system administration or even to traditional telephony, than to programming. Plus specifics of telephony — are better not to load with unfamiliar experiments the working systems once again, and to carry out tests and experiments on the notebook — it is necessary to litter system. Generally, there are many reasons "to postpone for later".

I want to show in this article to everyone and working with an asterisk as, using docker, it is possible to feel taste of the flexible scenarios lua quickly. And then to these it is worth deciding to use further in practice or not. (To whom it is uninteresting to read, and it is interesting to watch and listen — at the end of the text to 6-minute video with highlights and result.)

Asterisk + LUA: fast start

Parenthesis


Within work on the several projects, following a current trend of packaging of all in containers, I prepared an image of astolua (asterisk + lua). Commands for the asterisk 11, lua 5.1, luarocks installation (the package manager for lua), by luamongo (the driver for access to mongodb), some packets of lua rocks are given in Dockerfile. You can only take further in repositories of docker-astolua useful to yourself and bring together the working horse.

Certainly plus of the docker is an opportunity to download an image, to carry out tests-experiments-tests, and then to delete images, having left the operating system in purity and a usual order.

On the basis of an image of astolua we will create the working image in which we will use test files of a configuration of an asterisk and dialplan on lua.

Preparation


We will need docker. If at you it is not set, then, please, set at first docker (article on Habré).

Also we will need git (git installation)

Also at once I will note that my working system is Ubuntu 14.04. If you use other Linux, then difference in commands in principle should not be, but nuances are not excluded.

Loading of an image of astolua


We tighten an image (attention, the image from a repository of hub.docker.com by the size ~ 600 MB will be downloaded).

docker pull antirek/astolua


Sample


We clone docker-astolua-sample - it is in advance prepared file set for this article.

git clone https://github.com/antirek/docker-astolua-sample.git
cd docker-astolua-sample


Now let's stop on sample and we will look at directory contents.

Dockerfile file

The file for assembly of our working image. We specify in it that we take astolua as a basis. Then we add a script of automatic loading of after_start.sh which will be executed at start of the container. In the console where we will start the container, budt to be displayed the asterisk console log.

Build file

In the file command of the docker for creation of an image of sample from our Dockerfile.
docker build -t "astolua:sample" .


Run file
In the file command of the docker for start of the container on the basis of an image of sample with configuring of resources necessary for it.

docker run \
 -v /etc/localtime:/etc/localtime:ro \
 -v $(pwd)/store/etc/asterisk:/etc/asterisk \
 -v $(pwd)/store/var/log/asterisk:/var/log/asterisk \
 -v $(pwd)/store/var/menu:/var/menu/ \
 --net=host \
 -i -t "astolua:sample"


Store folder
The store folder contains configuration files of an asterisk (those which usually lie in / etc/asterisk) and folders for logs and voice menus.

The run command is most interesting since here necessary resources for the container are specified. For example, an option - v of $ (pwd)/store/etc/asterisk:/etc/asterisk we specify that configuration files from our store folder have to appear in the container on the place in / etc/asterisk.

Why commands in files? It is convenient to edit commands in files since it accelerates time on to test changes in commands with different options, and also all changes will lay down under control of versions. And it is still convenient to transfer then options to docker-compose if the image is used together with others.

Let's return to the console.

Let's make an image of astolua:sample (in a directory where we sklonirovat docker-astolua-sample)
./build


We start asterisk (if at you the asterisk or other service occupying port 5060 is already started by the machine, then it is better to stop it previously)
./run


In the console the log of loading of an asterisk has to be tumbled down. It is possible to test communication.

In a configuration file of an asterisk sip.conf two subscribers 101 and 102 (the password of 1234), and in the queues.conf file queue 1234 to which these two subscribers are added are specified. Configure the softphone or a hardphone on 101 subscribers and try to make a call on the subscriber 102. (There are no trunks for connection to external voip-services or settings of any iron therefore dialplan we will test on local calls). Information on a call between subscribers has to appear in the asterisk console.

Subscribers work, calls pass? Ok, the asterisk in the docker container means works as it is necessary.

Dialplan lua


Dialplan of lua is in the extensions.lua file. In configuration files of an asterisk in the store/etc/asterisk folder there is an example of the working dialplan of lua.

In this file the extensions and hints variables (in terminology of lua are "tables") have to be correctly described.

The table extensions contains contexts and the corresponding extensions. In total as in a traditional dialplan. But each extension is processed by the function in which you can already do anything on lua, at the same time interacting with an asterisk through the tables app and channel.

The simplest example

extensions = {
    ["internal"] = {
        ["_1XX"] = function (context, extension)
            -- do something --
            app.dial('SIP/'..extension);
            -- do something again
        end;
    }
}


It is visible that through app the application of a dialplan Dial is available, it accepts the same parameters, as in a traditional dialplan. Through app all applications of a dialplan are available.

The channel variable gives access to channel variables. Here so, for example, we receive dialstatus.

extensions = {
    ["internal"] = {
        ["_1XX"] = function (context, extension)
            -- do something --            
            app.dial('SIP/'..extension);
            local dialstatus = channel["DIALSTATUS"]:get();
            app.noop('dialstatus: '..dialstatus);
        end;
    }
}


You can change extensions.lua, and then command in CLI asterisks of module reload pbx_lua.so to re-read extensions.lua. The asterisk will check syntax of lua and if everything is OK, then loads it for execution — it is possible to test changes.

And what else it is possible to do in the dialplena of lua?

For example, flexibly to process dialstatus which will be returned by the Dial function of a dialplan. It is not necessary to invent more these Goto (s-of $ {DIALSTATUS}, 1), now it is possible to write verification of the status properly

extensions = {
    ["internal"] = {
        ["_1XX"] = function (context, extension)
            app.dial('SIP/'..extension);

            local dialstatus = channel["DIALSTATUS"]:get();
            if dialstatus == 'BUSY' then
                -- do something       
            elseif dialstatus == 'CHANUNAVAIL' then 
                -- do another thing
            end;
        end;
    }
}


In an example of extensions.lua there is an example of simple ivr: having called on number 200, you will hear record from file/var/menu/demo and will be able to pass further, having clicked 1 or 2.

local ivr = function (context, extension)        
    app.read("IVR_CHOOSE", "/var/menu/demo", 1, nil, 2, 3);
    local choose = channel["IVR_CHOOSE"]:get();

    if choose == '1' then
        app.queue('1234');
    elseif choose == '2' then
        dial('internal', '101');
    else
        app.hangup();
    end;
end;


For the person who wrote couple of tens of lines of a traditional dialplan everything has to be familiar here. Plus appears all power of lua and packets of luarocks. I hope obviously that here in the dialplena you can send SMS, an email, to put data in a DB, to take data from a DB, and the DB can be any: mysql, mongodb, redis, etc. to make an instruction fetch, to initiate one more call, to make abrupt routing of a call by trunks, etc., without forgetting, of course, that all this works within an asterisk, and it is better to solve all "heavy" problems after all separately.

What's next?


I offer:


I hope, this article will be useful to fast start, and you will find one free winter evening and will try such method of writing of dialplan.



Errors? Opechyatki? Questions? Please, write.

This article is a translation of the original post at habrahabr.ru/post/271939/
If you have any questions regarding the material covered in the article above, please, contact the original author of the post.
If you have any complaints about this article or you want this article to be deleted, please, drop an email here: sysmagazine.com@gmail.com.

We believe that the knowledge, which is available at the most popular Russian IT blog habrahabr.ru, should be accessed by everyone, even though it is poorly translated.
Shared knowledge makes the world better.
Best wishes.

comments powered by Disqus