• Пожалуйста, заметьте, что AEL до сих пор рассматривается EXPERIMENTAL

The Asterisk Extension Language (Язык Расширения Астериска)


Со временем люди были натолкнуты для того, чтобы добавить признаки к extensions.conf для того, чтобы сделать его более похожим на язык программирования. AEL планировался для того, чтобы предоставить настоящий язык программирования, который мог быть использован для написания диалплана Астериска.

Подготовка


Парсер AEL (pbx_ael.so) полностью отделен от модуля, который анализирует extensions.conf (pbx_config.so). Для того, чтобы использовать AEL, единственная вещь, которую надо сделать—это модуль pbx_ael.so должен быть загружен Астериском. Это делается автомтически, если используется “autoload=yes” в /etc/asterisk/modules.conf. Когда модуль загружен, он будет искать “extensions.ael” в /etc/asterisk/. Оба extensions.conf и extensions.ael могут быть использованы в конъюнкции с любым другим, если это требуется. Некоторые пользователи могут хотеть сохранить extensions.conf для признаков, которые сконфигурированы в сегменте “general” файла extensions.conf.

Перезагрузка extensions.ael


Для того, чтобы перезагрузить extensions.ael, следующая команда должна быть выдана в CLI.

*CLI> ael reload

Отладка


Разрешает отладку контекстов AEL
*CLI> ael debug contexts

Разрешает отладку макросов AEL
*CLI> ael debug macros

Разрешает отладку AEL операции чтения блока
*CLI> ael debug read

Разрешает отладку AEL лексем
*CLI> ael debug tokens

Отключает отладочные сообщения AEL
*CLI> ael no debug

Контекст


Контекст в AEL представляет множество расширений, которые делают то же, что и в extensions.conf.


context default {

};


Замечание: Открытая фигурная скобка может появиться сверху. Передвижение ее на следующую строку может иметь плохие последствия!

Расширения


Для того, чтобы определить расширение в контексте, должен использоваться следующий синтаксис. Если в приложении вызвано более одного расширения, они могут быть перечислены надлежащим образом внутри блока.


context default {
1234 => Playback(tt-monkeys);
8000 => {
NoOp(one);
NoOp(two);
NoOp(three);
};
_5XXX => NoOp(it's a pattern!);
};


Включения


Контексты могут быть включены в другие контексты. Все включенные контексты перечисляются внутри отдельного блока.


context default {
includes {
local;
longdistance;
international;
};
};


Переключатели Диалплана


Переключатели перечисляются в отдельном блоке внутри контекста.


context default {
switches {
DUNDi/e164;
IAX2/box5;
};
eswitches {
IAX2/context@${CURSERVER};
};
};


Ignorepat


ignorepat может быть использован, чтобы сообщить драйверам канала не отменять dialtome по получению конкретного шаблона. Наиболее часто используемым примером является “9”.


context outgoing {
ignorepat => 9;
};


Замечание: Открытая фигурная скобка может появиться сверху. Передвижение ее на следующую строку может иметь плохие последствия!

Переменные


Переменные в Астериске не имеют типа, поэтому чтобы определить переменную, она может быть прямо опеределена значением.

Глобальные переменные устанавливаются в своем собственном блоке.


globals {
CONSOLE=Console/dsp;
TRUNK=Zap/g2;
};


Замечание: Открытая фигурная скобка может появиться сверху. Передвижение ее на следующую строку может иметь плохие последствия!

Переменные также могут быть установлены внутри расширений.


context foo {
555 => {
x=5;
y=blah;
divexample=10/2
NoOp(x is ${x} and y is ${y} !);
};
};


Замечание: Астериск beta1 анализирует присваивания, используя упаковщик $[] как противоположность многим логическим методам выполнения этого, таким как Set and SetVar конструкции. В этом примере у меня есть ${ARG1}, устоновленный в “SIP/x7065558529” без кавычек и это исключили.
Замечание: Другое мнение: $[ ] позволяет выражениям использоваться и добавляет дополнительную силу языку. Прочитайте README.variables про требования выражений $. В следующем примере SIP/x7065558529
Замечание:

Функция записи в Диалплан рассматривается так же, как запись в переменную.


context blah {
s => {
CALLERID(name)=ChickenMan;
NoOp(My name is $WARNING: No such module CALLERID! !);
};
};


Циклы


AEL имеет реализации циклов “for” и “while”.


context loops {
1 => {
for (x=0; ${x} < 3; x=${x} + 1) {
Verbose(x is ${x} !);
};
};
2 => {
y=10;
while (${y} >= 0) {
Verbose(y is ${y} !);
y=${y}-1;
};
};
};


Замечание: Условное выражение ( “${y} >= 0” выше) заключено в $[ ], поэтому оно может быть вычислено.
Замечание: Текстовое выражение цикла for (“${x} < 3” выше) заключено в $[ ], поэтому оно может быть вычислено.

Условные выражения


AEL поддерживает выражения if и switch. Заметьте, что если у вас есть предложение else, вы ДОЛЖНЫ использовать скобки вокруг части не-else оператора if.


context conditional {
_8XXX => {
Dial(SIP/${EXTEN});
if ("${DIALSTATUS}" = "BUSY") {
Voicemail(${EXTEN}|b);
} else
Voicemail(${EXTEN}|u);
};
_777X => {
switch (${EXTEN}) {
pattern N11:
NoOp(You called a N11 number-- ${EXTEN});
break;
case 7771:
NoOp(You called 7771!);
break;
case 7772:
NoOp(You called 7772!);
break;
case 7773:
NoOp(You called 7773!);
// fall thru-
default:
NoOp(In the default clause!);
};
};
};


Замечание: Условное выражение в операторах if (“${DIALSTATUS}” = “BUSY” выше) заключено в $[ ] для вычисления.
Замечание: Значения ни switch, ни case не заключаются в $[ ]; они могут быть константами или ${var} указателями типа только.
Замечание: Использование “pattern” вместо “case” разрешает употребление Asterisk Dialplan Patterns.
Замечание:
Замечание: Так как переключатели вводятся как расширения, ${EXTEN} не будет работать, как хочется.

Goto и метки


Пример использования goto в AEL.


context gotoexample {
s => {
begin:
NoOp(Infinite Loop! yay!);
Wait(1);
goto begin; // переход к метке того же самого расширения
};
3 => {
goto s|begin; // переход к метке другого расширения
};
4 => {
goto gotoexample|s|begin; // overkill переход к метке того же самого контекста
};
};

context gotoexample2 {
s => {
end:
goto gotoexample|s|begin; // переход к метке другого контекста
};
};


Замечание: Метки goto позволяют одинаковым требованиям, таким как приложение Goto(), кроме последнего значения, должны быть меткой. Если метка не существует, у вас будет ошибка времени выполнения. Если метка существует, но в другом расширении, вы должны определить как имя расширения, так и метку в goto, как в: goto s|z; если метка находится в другом контексте, вы указываете контекст|расширение|метка. Это замечание об использовании goto в операторе switch выше…

Jumps


Для вызова другого расширения (или в операторе switch другого case) используйте оператор “jump”.


context incoming {
s => {
NoOp(Handle the call here);
};
18665551212 => jump s; // we accept POTS calls at this number
};

context home {
399 => jump s@incoming; // 399 is my 'simulate incoming call' speeddial ;)
};


Макросы


Макрос определяется в своем собственном блоке подобно этому. Аргументы макроса устанавливаются с именем макроса. Они поэтому отсылаются к тому же самому имени. Блок-“ловушка” может быть определен для того, чтобы поймать специальное расширение (добавочный телефонный номер).


macro std-exten( ext , dev ) {
Dial(${dev}/${ext},20);
switch(${DIALSTATUS) {
case BUSY:
Voicemail(b${ext});
break;
default:
Voicemail(u${ext});

};
catch a {
VoiceMailMain(${ext});
return;
};
};


Макрос вызывается предшествующим именем с амперсандом.


context example {
_5XXX => &std-exten(${EXTEN}, "IAX2");
};


Примеры



context demo {
s => {
Wait(1);
Answer();
TIMEOUT(digit)=5;
TIMEOUT(response)=10;
restart:
Background(demo-congrats);
instructions:
for (x=0; ${x} < 3; x=${x} + 1) {
Background(demo-instruct);
WaitExten();
};
};
2 => {
Background(demo-moreinfo);
goto s|instructions;
};
3 => {
LANGUAGE()=fr;
goto s|restart;
};
500 => {
Playback(demo-abouttotry);
Dial(IAX2/guest@misery.digium.com);
Playback(demo-nogo);
goto s|instructions;
};
600 => {
Playback(demo-echotest);
Echo();
Playback(demo-echodone);
goto s|instructions;
};
# => {
hangup:
Playback(demo-thanks);
Hangup();
};
t => goto #|hangup;
i => Playback(invalid);
};


Советы и ошибки


Замечание: Эти советы/ошибки для Астериска 1.2.1, воможно некоторые из этих ограничений будут удалены в будущем.

  • Каждая закрывающаяся “}” должня завершаться точкой с запятой “;”, включая операторы if, контексты, макросы, операторы switch, расширения и т.д. Если вы не сделаете этого, некоторые операторы между закрывающейся скобкой и следующей найденной “;” могут быть проигнорированы и не будет вызвано предупреждение, это может быть трудно для отладки.
  • Вы можете не иметь пустого оператора case.
  • Никогда не используйте “:” вне конструкции метки, анелизатор не проверит чтоб увидеть, если двоеточие сожержится внутри кавычек или внутри вызова функции (даже одна подобная NoOp, если вы пытаетесь напечатать отладку)
  • Когда используете метки, никогда не помещайте одну в самом конце макроса или расширения в контексте, всегда убеждайтесь, что хотя бы одна команда (такая как NoOp) есть после метки, иначе метка не добавится к диалплану. (Часто удобно иметь метку в конце упорядоченности для использования команды goto для обработки ошибки исключений).
  • Когда в операторе switch вы не можете просто выдавать goto для метки внутри такого контекст/расширение/макрос, потому что оператор switch создает новое расширение в текущем контексте вдля каждого оператора case, вы можете указать полное расположение метки в текущем контексте, подобно “goto s|mylabel” вместо “goto mylabel” или избегать операторов goto внутри операторов switch.
  • При вызове “FastAGI” вы должны избегать бекслеши, например: AGI(agi:\/\/127.0.0.1\/…).

Примеры


Здесь вы можете найти некоторые примеры, как использовать AEL для создания хороших диалпланов: AEL Example Snippets.