This article summarizes the intermediate results in developing my applications for asterisk. It all started during the New Year holidays, when I wanted to make a
quick voice dialing on asterisk . Then the
search for the direction by caller number was implemented (useful thing for incoming calls to 8-800 numbers). Then there was a pair of custom projects. And recently also
LCR for asterisk . All these applications are developed using the
ding-dong library, which allows you to work with AGI (Asterisk Gateway Interface) in the node.js application.
Next, I would like to show that using node.js and ding-dong, you can quickly develop useful applications for asterisk.
During these six months,
ding-dong (fork of the
node-agi project) began to support the promise style (thanks to my colleague Denis), as well as the full range of AGI functions.
But before writing the application I want to talk a little about the other first. Next, a little in the format of the conversation "with himself."
')
What is the problem, bro?I configure asterisks a lot. Often, customers require interesting pieces that are quite realistic for themselves to implement using an asterisk. Moreover, it is often possible to implement the required functionality in different ways. But often the addition of this functionality complicates the asterisk dialplan so much that it becomes difficult to maintain all the chips in working condition.
Moreover, if one person has somehow been configured and configured, then it is fit to write a manual on how to figure out the other one and correct or reconfigure something.
Here is
an example of a great recipe for single playback. And you want to come up with a chip, develop, test, and only then put on the client's working system, and even quickly and with minimal changes. And all other customers to put one little finger.
Many people use products like FreePBX or Elastix, where typical things are performed in a typical way. But if something is non-standard, then "scripting" in files of the type "* _custom.conf" begins
And what do you suggest?Not a silver bullet, of course. Roughly speaking, the asterisk dialplan can be divided into two parts: the actual routing of the call and the accompanying auxiliary calculations, the result of which determines the further route of the call.
So we must bring these calculations beyond the limits of the asterisk dialplan.
This approach is very well illustrated by the applications agi-number-archer and lcr-finder, i.e. at the entrance we give the phone number, at the exit we get the name or code.
lcr-finder: as a result, it gives the name of the operator with the lowest cost of the call for the called number.
agi-number-archer: as a result, gives the region by caller number.
The dialplan of the asterisk that uses such an application absolutely does not know how this service works, it works on node.js or twisted, the MySQL or MongoDB database is used. Moreover, the dialplan should be written in such a way as to have the option of passing the call in the absence of data from the service.
For example, in the lcr-finder it became possible to disconnect the operator from the least cost search, but from the point of view of the asterisk dialplan, nothing has changed, the application has updated, and in a working asterisk even the 'dialplan reload' was not done.
Still as an example. The first version of voicer sent a command to call the asterisk by the number found. The current version of voicer simply returns the number found, allowing the dialplan to analyze the result, make the call, handle the call status.
OK, AGI is cool. And why the server, and not the script?Because it is a fully working service that is ready at any moment to respond to an AGI request that keeps logs about its work.
I also have several asterisks working on the same network, for each of them to raise my own server to determine the direction is somehow redundant, updating the script also on all the machines was more time-consuming task than on one.
Moreover, the presence of the monitoring system and the process manager also help. The monitoring system will monitor the server that is running, detailed logs will help to clarify the details, and restart the process manager (such as pm2) in the event of a crash due to errors in processing requests.
* It should be noted on the whole of this approach was influenced by the
manifest of 12 factorial applications (
translation ).
OK, server. And why node.js?Mmm, should have taken php? But seriously, the same
can be done in php . But I liked the use of npm to quickly develop and distribute the application. Initially, the callback functions were strained, but now the ding-dong supports the promise style, so you can write neat scripts, including cyclic ones (see the voicer code).
Maybe something more productive than node.js? I do not have millions of requests per second, everything works ok. Perhaps, on more loaded systems it is necessary to use something else (although the asterisk also may have to be changed).
Are there alternatives to ding-dong?Of course, for example, recently there was a
great option for an agi-server on js. It has a mapper of requests to AGI, i.e. You can describe several scenarios and hang them on different uri_string on the same port, for php there are phpagi,
fast-pagi . In general, the point is not in the programming language, but in the approach.
Can we already write helloWorld using AGI?So. Let's see how ding-dong can help us quickly develop an application.
The main feature of using AGI is the transfer of the work of managing a dialplan to a third-party application, i.e. our server. Let's write such a simple dialplan.
extensions.conf [default] exten => _X.,1,AGI(agi://localhost:3000) exten => _X.,n,Verbose(DIALPLAN_VARIABLE)
Your subscriber's call to the default context will be monitored by an AGI server. Let's write a simple AGI server.
var AGIServer = require('ding-dong'); var handler = function (context) { context.onEvent('variables') .then(function (vars) { return context.answer(); }) .then(function () { return context.streamFile('beep'); }) .then(function (result) { return context.setVariable('DIALPLAN_VARIABLE', 'helloWorld'); }) .then(function (result) { return context.end(); }); }; var agi = new AGIServer(handler); agi.start(3000);
Now, saving and reloading the dialplan, launching the AGI server, make a call. We have to hear the "beep", and in the asterisk console in verbose helloWorld should be displayed.
To our AGI server, which is running on port 3000, we have to give the handler function, which will drive the call. To interact with the channel there is a context. When a call arrives at the AGI server, the variables event occurs. When calling, the vars data set is also transmitted. It contains time, dialed number, peer caller and more.
Also further through context we can send commands to the call channel, here in the example context loses the sound beep with the streamFile command.
At the end, we do context.end (), which closes the session. Dialplan asterisk passes on.
The example also has context.setVariable (), a function that sets a dialplan variable. Those. we can save our result to the dialplan variable, and then the dialplan itself will decide what to do with it. This variable may have a peer name, where to call, or an order number, or something else.
Also using context we can send commands to receive DTMF, write to the file, pronunciation of numbers and other functions of the asterisk.
And, of course, in the handler, we have to do all the useful work for which we sent the call control to AGI, be it data retrieval in the database, speech recognition, something else.
This example is on github:
github.com/antirek/ding-dong-sampleDisadvantages?Overall, quite comfortable. Perhaps the most inconvenient thing you had to deal with was the impossibility of transferring files via AGI. Those. if an asterisk knew how to write a file, and then transfer it via AGI, then voicer would be a bit easier to configure.
What else can be realized with this approach?For example, I suppose that some of the tasks (
one ,
two ,
three ,
four ) could be solved by writing a small AGI server and giving it a search for a solution, rather than writing scripts in bash. And it would be more convenient to use.
Also, for example, you can implement an alert on the status of the order when you enter the order number by the DTMF, gather information about completed work on requests, listen to files. Those. for writing small, simple and functional scripts is enough.
And in the end?Of course, AGI is not the first day. And there are already many scripts and applications that use this method of interaction with the asterisk, sharing with it the tasks it performs. I hope that these applications, as well as the information presented in the note, will be useful.
ding-dong ,
voicer ,
agi-number-archer ,
lcr-finderAGI functions
on the Asterisk siteI would be happy to comment on the article, proposals for the development, constructive criticism.