Freeswitch XML Dialplan
https://freeswitch.org/confluence/display/FREESWITCH/XML+Dialplan
Created by Jim Hayes, last modified by Ryan Harris
Перевод Олег Звездочкин.
XML диалплан используется Freeswitch по умолчанию.
Основная задача диалплана маршрутизация вызова к конечной точке ( endpoint), которой может быть традиционный внутренний абонент атс, voicemail, ivr (интерактивное голосовое меню), очередь колл центра (queue), группа внутренних абонентов или внешний номер. Диалплан очень гибок.
Диалплан может быть разделён на контексты (contexts), которые группируют наборы расширений (extensions). Контекст может быть присвоен sip профилю или транку и др. Вызовы могут передаваться из контекста в контекст. Например, по умолчанию, в ванильной конфигурации FS, диалплан раделен на два контекста, внешний - public и внутренний - default. Вызовы приходящие через внешний контекст, пройдя предварительную обработку перенаправляются во внутренний контекст для вызова расширений (extensions).
Контексты диалплана, также позволяют создавать многопользовательские (multi-tenant) АТС, на базе одного сервера. Каждый тенант может иметь собственные расширения и другие ресурсы в собственных контекстах диалплана не конфликтуя с другими.
Простые диалпланы легко создаются с минимальными знаниями о регулярных выражениях.
В создании умеренно сложных XML диалпланов поможет глубокое понимание PCRE, а также представление о переменных, массивах и управлении потоками в скриптовых языках программирования.
Цель обучения
После изучения данной документации вы научитесь:
- Привязывать sip профили к контекстам диалплана для совершения вызовов.
- Создавать хорошо управляемый диалплан используюший регулярные выражения, для вызовов множества расширений через единый шаблон.
- Понимать потоки обработки вызовов через условия и вложенные условия.
- А также, почему и где эти условия применяются в диалплане.
Предварительный обзор
Когда вызов поступает в АТС, Sofia первой принимает его. Она собирает информацию о вызове и определяет какой контекст должен быть использован.
Sofia передает информацию
при помощи переменных канала назначенных вызову,
которые диалплан использует для манипуляций с вызовом.
Переменные содержат подробную информацию о вызове:
Например переменная destination_number
содержит цифры набранные вызывающим абонентом, другие переменные содержат инф. о CallerID, IP адресе звонящего и т.п.
XML дилплан организован как серия расширений (extensions). Диалплан пошагово проверяет все известные ему расширения, пока не найдет подходящее. Диалплан может остановиться после первого совпадения условий или продолжить проверку, это зависит от дополнительных параметров, указанных в условии/условиях расширений. Об этом будет подробно рассказано позже. Совпадение находится путем оценки условий (conditions) внутри каждого расширения. Множество условий могут быть назначены в одном расширении, диалплан найдя совпадение, будет продолжать проверять условия уже внутри расширения.
Когда все условия найдены и обработаны диалплан переходит к действиям (actions). Простейший пример действия, вызов физического устройства и соединение с ним. Широкий набор действий может быть определен в диалплане. По ходу данного обзора мы познакомимся с некоторыми из них.
Если вложенные условия не совпадают в пределах одного расширения, возможно указать анти-действия (anti-actions) которые будут выполнены.
XML диалплан базовая концепция, изучение которой требуется для работы с FS. Если вы хорошо знакомы с другими скриптовыми языками программирования, то понять логические операции и течение потоков обработки диалплана, не составит особого труда и вы сможете создавать сложные продвинутые сценарии. Но XML не может решить всех задач возникающих при создании современных систем связи. Обширный XML диалплан может быть запутанным и сложным для понимания. Для решения нетривиальных задач существуют дополнительные процессоры диалплана. Диалплан можно писать на Lua, Python, Javascript и т.п. Чаще всего используется Lua.
Вводный пример
Следующий пример показывает маршрутизацию вызова на два екстеншена, 500 и 501.
Перед тем как использовать его, потребуется привязать наш диалплан в sip профиле параметром context
.
Устройства зарегистрированные через этот профиль будут использовать указанный диалплан.
<profile name="example_sip_profile"> <param name="context" value="example"/> ...other configuration statements... </profile> |
Пример диалплана:
<context name="example"> <extension name="500"> <condition field="destination_number" expression="^500$"> <action application="bridge" data="user/500"/> </condition> </extension> <extension name="501"> <condition field="destination_number" expression="^501$"> <action application="bridge" data="user/501"/> <action application="answer"/> <action application="sleep" data="1000"/> <action application="bridge" data="loopback/app=voicemail:default ${domain_name} ${dialed_extension}"/> </condition> </extension> </context> |
Когда выполняется вызов, оценивается каждое расширение пока не будет найдено совпадение.
Первая строка примера содержит блок <context name="example">...</context>
. Все определения в этом блоке относятся к диалплану по имени «example».
Вложения внутри контекстного блока, являются блоками расширения, содержащими соответствующие "conditions" и соответствующие им правила "actions". Расширения обрабатываются в том порядке, в котором они отображаются в файле конфигурации.
В примере Sofia выполнит диалплан когда получит входящий вызов.
Предположим вызывается номер 501:
- Первое расширение игнорируется, т.к. не совпадает условие по
destination_number
. - Второе расширение совпадает по условию и будет вызван номер 501,
- если он не ответит, вызов будет отвечен приложением
answer
, - будет выдержана пауза 1000ms
- и вызов будет перенаправлен на голосовую почту.
Информация к размышлению
- Найдите
action
в примере, который переводит вызов на голосовую почту.- Обратите внимание на переменные канала domain_name и dialed_extensions и как они передаются в приложение
voicemail
. - Вы можете создавать и задавать собственные переменные, такие как эти, в своем диалаплане.
- Подумайте будут ли они переданы? Если нет, то почему?
- Диалплан прекращает выполнение дополнительных действий, как только вызов будет соединен (bridge) с другим екстеншеном или передан в другой диалплан. Это значит, что в нашем примере, если 501 ответит последующие действия не будут выполнены после окончания вызова (но это поведение по умолчанию можно изменить).
- Создание диалплана указанным способом для вызова множества расширений может быть очень нудным и не очень эффективным занятием. Возможно ли создать диалплан, в котором 1000 расширений будут вызываться одним определением?
Возможно приведенный пример вообще не будет работать, почему? |
Структура директорий и файлов диалплана
Конфигурационные файлы диалплана Freeswitch хранятся в ../conf/dialplan (или /etc/freeswitch/dialplan ). Каждый контекст и его расширения вынесенные в отдельные файлы храняться в поддиректориях, обычно имеющих то же имя, что и контекст. Это не обязательная, но рекомендованная структура.
Пример структуры файлов диалплана для простой АТС:
freeswitch/ conf/ dialplan/ public.xml public/ 00_security_screen.xml 10_inbound_sip-bandwidth-r-us.xml 29_inbound_sip-super-call.xml ... default.xml default/ 00_feature_codes.xml 05_voicemail_access.xml 20_extension_2001.xml 20_extension_2002.xml ...
Информация к размышлению
- Данная структура это простой пример, который может послужить хорошей отправной точкой для создания вашей собственной структуры диалплана.
- Любой .xml файл помещенный в директорию diaplan, будет загружен при старте FS.
- public.xml содержит содержит общую конфигурацию для контекста
public
, включая все файлы в директории public. - default.xml содержит общую конфигурацию для контекста
default
, включая все файлы в директории default. - Файлы загружаются и читаются в алфавитном порядке, так что начинать имена файлов с цифр это хорошая практика, которая позволяет контролировать порядок обработки расширений.
Базовые концепции
Context
Единственный параметр контекста, это его имя. Это имя использует Sofia (или любой другой драйвер канала FS) для отправки вызовов в маршрутизацию:
Sip_profile → Context → Extensions(Conditions(Actions)) |
Понятие контекста FS немного другое, чем, например, понятие контекста Asterisk.
Для создания комплексного диалплана
в рамках одного домена, вполне можно обойтись двумя базовыми контекстами, а роль контекстов в понимании Asterisk, будут выполнять обусловленые расширения.
Во главе угла тут стоят conditions - условия определяют выбор екстеншена, а контекст определяет набор extensions доступных данному профилю.
<param name="context"...
как правило задается профилю (sip_profile), но этот параметр можно задать и gateway (транку).
Ну и конечно можно передавать вызовы из контекста в контекст из расширений.
<context name="default"> <!-- one or more extension tags --> </context> |
Extensions
Имя extensions не связано напрямую с вызываемым телефоном. Параметр name
должен быть уникальным. Другие контексты могут передавать управление вызовом используя это имя.
Расширения используются для маршрутизации вызовов, установки ограничений, выбора транков и др.
Внутри расширения может содержаться одно или более условий (conditions). Если совпадение есть, выполняются действия (actions), если нет, могут быть назначены anti-actions.
Пример:
<extension name="Your_extension_name_here"> <condition(s)... <action(s) .../> <anti-action(s) .../> </condition> </extension> |
Обычно, когда совпадение найдено соответствующие действия выполняются и выполнение диалплана останавливается.
Однако дополнительный параметр continue
разрешает продолжить оценку остальных расширений диалплана:
<extension name="500" continue="true">
|
Conditions
Условия сравнивают заданные регулярные выражения с переменными присвоенными вызову.
Первый пример просто ожидает совпадения переменной destination_number
с номером «500»:
<extension name="500"> <condition field="destination_number" expression="^500$"> <action application="bridge" data="user/500"/> </condition> </extension> |
Условия используют Perl Compatible Regular Expression library. (См. документацию Perl Compatible Regular Expression)
Пример 1: Capturing Digits
Следущий пример демонстрирует как удалить цифры из набранного номера при помощи PCRE. (Отрежем код страны и города для городского вызова в локальной тлф. сети)
В России, последние 7 цифр из 11 являются локальной частью номера. (По крайней мере для миллионников). Так, если наша АТС находится в Санкт Петербурге первые четыре цифры не надо транслировать в городскую телефонную сеть, они всегда будут 8812:
<condition field="destination_number" expression="^8812\d\d\d\d\d\d\d$">
|
Условие совпадает с любым 11-значным номером, начинающимся с "8812“. Захватим последние 7 цифр, заключив их в круглые скобки:
<condition field="destination_number" expression="^8812(\d\d\d\d\d\d\d)$">
|
Условие все также совпадает с 11-значным номером «8812…….», но последние 7 цифр будут сохранены в переменной $1
.
Эту временную переменную мы и используем для вызова в городскую тлф. сеть:
<extension name="local_calls"> <condition field="destination_number" expression="^8812(\d\d\d\d\d\d\d)$"> <action application="bridge" data="sofia/gateway/LocalTelco/$1"/> </condition> </extension> |
destination_number
изначально - 88123216111 сохранен через $1
, как 3216111 и в таком виде отправлен в Петербургскую Тлф. Сеть.
Чтобы добавить цифры за переменной заключите ее в брекеты (фигурн. скобки) - «sofia/gateway/LocalTelco/${1}5». |
Пример 2: Logical AND
Предположим вы хотите перенаправлять вызовы с «500» на «531», но только по воскресеньям.
В XML диалплане можно задавать больше одного условия в одном расширении. Если основное условие совпадает, будут проверяться вложенные условия и выполняться предусмотренные ими действия.
Вот тому пример:
<condition field="destination_number" expression="^500$"/> <condition wday="1"> <action application="bridge" data="sofia/internal/531@example.com"/> # если Воскр. (1-й день недели) вызываем 531 <anti-action application="bridge" data="sofia/internal/500@example.com"/> # если нет, то 500. </condition> |
anti-action
использованы, чтобы направить вызов в нужное место, если последнее условие не совпало.
Структура Conditions
- Синтаксис:
- Предварительные условия должны быть закрыты -
/>
. Они ее имеют вложенных действий, а только определяют выбор данного расширения. Условия содержащие финальные действия, обрамляют их:
<condition>…</condition>
.
- Они следуют за «предварительными» условиями, но могут обходиться и без них.
- Если «последнее» condition имеет вложенные условия, то они могут иметь вышеописанную структуру.
Пример 3: Logical OR
Есть несколько способов реализации. Используйте подходящий для ваших задач.
Простейший метод использует ИЛИ прямо в регулярном выражении. destination_number
совпадает с «501» или «502»:
<condition field="destination_number" expression="^501|502$"> action(s)... </condition> |
Этот метод хорош, если используется только одно полe (field) условия. Если требуется сравнение для двух или более разных полей, тогда используется расширенный синтаксис регулярных выражений FS:
<condition regex="any"> <regex field="some_field" expression="Some Value"/> <regex field="another_field" expression="^Another\s*Value$"/> <action(s) ...> <anti-action(s)...> </condition> |
Обратите внимание на regex="any"
в начальном условии.
Это говорит, что любое условие правда (true) и если какое-либо из последующих условий совпадет, то будут выполнены его действия.
Если ни одно из вложенных условий не совпадает, то будут выполнены anti-actions
, ибо any
всегда true.
Следующий пример выполняется, если caller_id_name
= «Some User» или если caller_id_number
= «1001»:
<extension name="Regex OR Example"> <condition regex="any"> <!-- If either of these is true then the subsequent actions are added to execute list --> <regex field="caller_id_name" expression="Some User"/> <regex field="caller_id_number" expression="^1001$"/> <action application="log" data="INFO At least one of the conditions matched!"/> <!-- If *none* of the regexes is true then the anti-actions are added to the execute list --> <anti-action application="log" data="WARNING None of the conditions matched!"/> </condition> </extension> |
<condition regex=…>
может принимать ещё два значения: all
и xor
. Рассмотрим все три значения подробнее:
regex="any"
- Мы использовали это выше. Любые данные совпадают с начальным условием, значит для любого вызова вложенные условия будут рассмотрены, а действия выполнены по их совпадению.regex="all"
- эквивалентно логической операции «AND». Все последующие условия должны совпасть, чтобы действия были выполнены. Это другой вариант реализации «AND» из примера 2. Данный синтаксис сделает ваш диалплан более удобочитаемым.regex="xor"
- логическая операция «XOR». «XOR» - обычно подразумевает «eXclusive-OR», т.е. только одно условие (exactly one) должно совпасть, чтобы действия были выполнены.- Действия и анти-действия выполняются также, как и в обычном блоке условий.
Рассмотрим подробнее данный метод.
Если caller_id_name
= «Michael S Collins» ИЛИ caller_id_number
= 1002, 3757 или 2816 переменная calling_user
будет назначена, как «mercutioviz», иначе же - «loser».
После воспроизведения общего приветственного сообщения будет проиграно сообщение выбранное на основании значения переменной calling_user
.
<extension name="Regex OR example 2" continue="true"> <condition regex="any" break="never"> <regex field="caller_id_name" expression="^Michael\s*S?\s*Collins"/> <regex field="caller_id_number" expression="^1001|3757|2816$"/> <action application="set" data="calling_user=mercutioviz" inline="true"/> <anti-action application="set" data="calling_user=loser" inline="true"/> </condition> <condition> <action application="answer"/> <action application="sleep" data="500"/> <action application="playback" data="ivr/ivr-welcome_to_freeswitch.wav"/> <action application="sleep" data="500"/> </condition> <condition field="${calling_user}" expression="^loser$"> <action application="playback" data="ivr/ivr-dude_you_suck.wav"/> <anti-action application="playback" data="ivr/ivr-dude_you_rock.wav"/> </condition> </extension> |
inline
Обратите внимание на опциюinline="true"
добавленную к действиям устанавливающим значение пользовательской переменной calling_user
. Обычно, когда обрабатывается расширение, все действия собираются вместе и выполняются ПОСЛЕ проверки всех условий. Но т.к. переменная calling_user
используется в последующих условиях, требуется назначить её сразу при совпадении условия к которому относится данное действие. Для этого и существует параметр inline
.
Т.е., если задан параметр inline="true"
действие будет выполнено НЕМЕДЛЕННО, а не после проверки всех условий. Данный параметр может применяться не ко всем типам действий (action application).
Без указания inline="true"
, третий блок условий в примере не будет выполнен.
Пример 4: Logical XOR
Мы рассмотрели использование regex= clause в отношении AND и OR. Для полноты приведем последний пример использования XOR. Действия в примере будут выполнены, если совпадет первое ИЛИ второе условие, но НЕ будут выполнены, если совпадают оба.
<extension name="Regex XOR example 3" continue="true"> <condition regex="xor"> <!-- If only one of these is true then the subsequent actions are added to execute list --> <regex field="caller_id_name" expression="Some User"/> <regex field="caller_id_number" expression="^1001$"/> <action application="log" data="INFO Only one of the conditions matched!"/> <!-- If *none* of the regexes is true then the anti-actions are added to the execute list --> <anti-action application="log" data="WARNING None of the conditions matched!"/> </condition> </extension> |
Actions and Anti-Actions
Последняя часть определения расширений это действия (action application). Действия логическое завершение расширения, они выполняют соединения и предоставляют другие функции. Список приложений (applications) весьма обширен, вы можете ознакомиться с ним здесь.
Action | Description |
---|---|
answer | Отвечает на вызов |
bridge | Совершает вызов |
log | Записывает событие в лог |
hangup | Разъединяет вызов |
playback | Проигрывает аудио файл или тональный сигнал |
set | Устанавливает переменную канала |
transfer | Передает обработку вызова другому расширению |
inline
примечание 1 В большинстве случаев вы не можете получить результат выполняемого действия СРАЗУ для проверки или использования в последующих <condition…>
или <action …>
.
Но это ограничение можно обойти, если передать обработку вызова в другое расширение (<action application=«transfer»…
). Тогда все действия первого расширения будут выполнены и [например] переменные назначены.
Или же выполнить действие «inline»:
примечание 2 Некоторые, но не все, приложения (applications) могут быть выполнены с параметром inline="true"
. Данный параметр чаще всего полезен в приложении set
. Список приложений в которых может быть использован "inline" приведен ниже, в этом документе
Anti-Actions
В нескольких предыдущих примерах, мы использовали выражение anti-action
. Само его имя подразумевает, что действие будет выполнено, если условие ложно.
Для каждого условия, если action
не может быть выполнено, anti-actions
будут выполнены и наоборот.
Dialplan Variables
Итак, мы рассмотрели основные концепции диалплана и его структуру. В примерах было показано использование:
- Extensions - расширений
- Conditions - условий
- Regular Expressions - регулярных выражений
- Actions and Anti-Actions - действий и анти-действий.
Теперь рассмотрим тему переменных. Они являются важной частью диалплана.
Переменные это именованные части информации сохраненные для последующего использования. Когда начинается выполнение диалплана, обширная часть информации загружается в переменные канала. Переменные сопоставляются с регулярными выражениями и определяют результат выполнения диалплана.
Рассмотрим несколько переменных канала, чтобы понять как они используются и преобразуются в диалплане FS.
Доступ к переменным
Есть три разновидности переменных доступных для использования в диалплане Freeswitch:
- * Переменные канала
- Глобальные переменные
- Встроенные переменные (time, date, etc.)
Переменные канала (Channel Variables)
В переменных канала храниться информацию о текущем вызове для контроля его прохождения через диалплан.
Channel variables содержат обширную коллекцию инфы о вызове, а также массив параметров, которые можно задавать в процессе обработки вызова диалпланом.
Доступ к переменным осуществляется по имени заключенном в ${}
, например для доступа к доменному имени по умолчанию, можно просто указать ${domain_name}
в строке набора, и имя будет поставлен:
<action application="bridge" data="user/1000@${domain_name}/>
|
Значение переменной канала задается так:
<action application="set" data="call_timeout=30"/>
|
Полный список Channel Vaiables и способы их использования можно посмотреть тут.
В этом же документе приведем короткий список часто используемых переменных:
Variable Name | Description |
---|---|
caller_id_name | Имя вызывающего абонента. |
destination_number | Вызываемый номер. |
direction | направление вызова inbound или outbound (также известные как: a-leg, b-leg) |
channel_name | Имя inbound канала, например:sofia/sales/John_Smith@192.168.1.1 |
call_timeout | Таймаут вызова в секундах. |
state | Состояние канала, например CS_EXECUTE или CS_HANGUP |
bridge_hangup_cause | Коды причин разъединения вызова, например NO_ANSWER , NORMAL_CLEARING или USER_BUSY |
Встроенные переменные (Built-In)
Доступ к встроенным (Built-In) осуществляется без префикса ${}
Встроенные переменные:
Built-In Name | Description |
---|---|
Стандартное: Дата и Время | |
date-time | Текущие дата и время: YYYY-MM-DD HH:MM:SS пример: 2014-08-12 15:34:59 |
time-of-day | Текущее локальное время: HH:MM:SS пример: 15:34:59 |
Дата и время составляющие (все для локальной временной зоны) | |
year | Текущий год. (от 1970 до 9999) |
mon | Месяц. (от 1 до 12) |
mday | День текущего месяца. (от 1 до 31) |
hour | Час текущих суток. (от 0 до 23) |
minute | Минута текущего час. (от 0 до 59) |
Дополнительные составляющие | |
wday | День недели. (Воскр. = 1 до 7) |
week | Текущая неделя с 1 Янв (от 1 до 53) |
mweek | Неделя текущего месяца. (от 1 до 6) |
yday | День текущего года (от 1 до 366) |
minday | Текущая минута с полуночи. (от 0 до 1440) |
tz-offset | Смещение временной зоны от Гринвича. (от -11 до +11) |
dst | Возвращает 1 если Летнее Время или 0 если нет. |
В операторах условий вы можете сравнивать с более чем одной встроенной переменной. Все сравнения должны соответствовать (логическому AND) до того, как будут выполнены его действия. Существует несколько способов совпадения со встроенной переменной. Вы можете:
Kind | Example | Description |
---|---|---|
Equality | <condition wday="1"> | Is it Sunday? |
Range | <condition wday="2-4"> | Is it Monday, Tuesday, or Wednesday? |
List | <condition wday="1,4"> | Is it Sunday or Wednesday? |
Combination | <condition wday="1-3,7"> | Is it Sunday, Monday, Tuesday, or Saturday? |
Диапазоны могут использоваться для времени и дат:
<condition time-of-day="08:00:00-09:00:00"> <condition date-time="2010-10-01 00:00:01~2010-10-15 23:59:59"> |
~
, а не -
Advanced Concepts
Nested Conditions
Условия могут быть вложены одно в другое. Вложенные условия довольно сложны. Возможно лучше использовать скриптовые расширения диалплана, такие как Fs: mod_lua.
Когда (основное) условие имеет вложенные (условия), сначала оценивается его выражение и его (основные) действия добавляются в список подготовленный к выполнению. Затем оцениваются вложенные условия.
Каждое условие подразумевает параметр require-nested
, который имеет значение по умолчанию - true
.
Когда у нас есть условие с require-nested = "true"
, тогда ВСЕ его вложенные условия должны быть истинными ( т е. основное условие И все вложенные, должны быть истинными), чтобы основное условие было оценено как истинное и все действия выполнены.
Если require-nested = "false"
, достаточно, чтобы только основное выражение было истинным, тогда независимо от оценки вложенных условий, его действия будут выполнены. Действия же вложенных будут выполнены, если они истинны.
Краткое резюме
require-nested="true"
:
Тогда оцениваются вложения и если они ВСЕ истинны, тогда выполняются действия в порядке перечисления. Если хоть одно из вложенных условий ложь, тогда ВСЕ условия считаются ложью и действия не выполняются.
Основное условие истинно, а
require-nested="false"
:
Тогда действия вложенных условий выполняются в зависимости от того ложны они или нет, независимо от истинности друг друга.
Также учитываются значения параметра break
.
«Поиграйтесь» с приведенным ниже примером, устанавливая параметры в разные возможные значения. Это поможет лучше понять механизм работы вложенных условий.
<extension name="nested_example"> <condition field="destination_number" expression="^2901$" require-nested="false"> <action application="log" data="ERR 00 CIDnum is ${caller_id_number} CIDname is ${caller_id_name}" /> <action application="set" data="var_01=N/A" inline="true"/> <action application="set" data="var_02=N/A" inline="true"/> <action application="set" data="var_03=N/A" inline="true"/> <action application="set" data="var_04=N/A" inline="true"/> <action application="set" data="var_05=N/A" inline="true"/> <action application="log" data="ERR 01 I'm before..."/> <action application="set" data="var_01=01" inline="true"/> <action application="log" data="ERR 02 I'm before ${var_01} ${var_02} ${var_03} ${var_04} ${var_05}"/> <condition field="caller_id_number" expression="1011" break="on-false"> <action application="log" data="ERR 03 I'm the first..."/> <action application="log" data="ERR 04 I'm the first CIDnum is ${caller_id_number}" /> <action application="set" data="var_02=02" inline="true"/> <action application="log" data="ERR 05 I'm the first ${var_01} ${var_02} ${var_03} ${var_04} ${var_05}"/> </condition> <action application="log" data="ERR 06 I'm in between..."/> <action application="set" data="var_03=03" inline="true"/> <action application="log" data="ERR 07 I'm in between ${var_01} ${var_02} ${var_03} ${var_04} ${var_05}"/> <condition field="${caller_id_name}" expression="Giovanni" break="on-false"> <action application="log" data="ERR 08 I'm the second..."/> <action application="log" data="ERR 09 I'm the second CIDname is ${caller_id_name}" /> <action application="set" data="var_04=04" inline="true"/> <action application="log" data="ERR 10 I'm the second ${var_01} ${var_02} ${var_03} ${var_04} ${var_05}"/> </condition> <action application="log" data="ERR 11 I'm after..."/> <action application="set" data="var_05=05" inline="true"/> <action application="log" data="ERR 12 I'm after ${var_01} ${var_02} ${var_03} ${var_04} ${var_05}"/> </condition> </extension> <extension name="call_has_not_stopped_before_here"> <condition field="destination_number" expression=".*"> <action application="log" data="ERR NOT STOPPED BEFORE HERE"/> </condition> </extension> |
Значения которые вы можете изменить:
- Выражения: 2901, 1011, Giovanni
- В первом условии,
require-nested
может бытьtrue
илиfalse
- Параметр
inline
для действияset
может быть установлен вtrue
илиfalse
- Параметр
break
во вложенных условиях может принимать значения:on-false
,on-true
,never
,always
require-nested="false"
"var_04=N/A" потому что отому что одно условие (caller_id_name) не совпало и переменной назначено значение "основного" условия:
Regex (PASS) [nested_example] destination_number(2901) =~ /^2901$/ break=on-false Regex (PASS) [nested_example_recur_1] caller_id_number(1011) =~ /1011/ break=on-false Regex (FAIL) [nested_example_recur_1] ${caller_id_name}(NOT_Giovanni) =~ /Giovanni/ break=on-false
[ERR] mod_dptools.c:1742 00 CIDnum is 1011 CIDname is NOT_Giovanni [ERR] mod_dptools.c:1742 01 I'm before... [ERR] mod_dptools.c:1742 02 I'm before 01 02 03 N/A 05 [ERR] mod_dptools.c:1742 06 I'm in between... [ERR] mod_dptools.c:1742 07 I'm in between 01 02 03 N/A 05 [ERR] mod_dptools.c:1742 11 I'm after... [ERR] mod_dptools.c:1742 12 I'm after 01 02 03 N/A 05 [ERR] mod_dptools.c:1742 03 I'm the first... [ERR] mod_dptools.c:1742 04 I'm the first CIDnum is 1011 [ERR] mod_dptools.c:1742 05 I'm the first 01 02 03 N/A 05
Все условия совпали, переменным переназначены значения из вложенных условий:
Regex (PASS) [nested_example] destination_number(2901) =~ /^2901$/ break=on-false Regex (PASS) [nested_example_recur_1] caller_id_number(1011) =~ /1011/ break=on-false Regex (PASS) [nested_example_recur_1] ${caller_id_name}(Giovanni) =~ /Giovanni/ break=on-false
[ERR] mod_dptools.c:1742 00 CIDnum is 1011 CIDname is Giovanni [ERR] mod_dptools.c:1742 01 I'm before... [ERR] mod_dptools.c:1742 02 I'm before 01 02 03 04 05 [ERR] mod_dptools.c:1742 06 I'm in between... [ERR] mod_dptools.c:1742 07 I'm in between 01 02 03 04 05 [ERR] mod_dptools.c:1742 11 I'm after... [ERR] mod_dptools.c:1742 12 I'm after 01 02 03 04 05 [ERR] mod_dptools.c:1742 03 I'm the first... [ERR] mod_dptools.c:1742 04 I'm the first CIDnum is 1011 [ERR] mod_dptools.c:1742 05 I'm the first 01 02 03 04 05
require-nested="true"
Действия не выполняются. потому что одно условие (caller_id_name) не совпало:
Regex (PASS) [nested_example] destination_number(2901) =~ /^2901$/ break=on-false Regex (PASS) [nested_example_recur_1] caller_id_number(1011) =~ /1011/ break=on-false Regex (FAIL) [nested_example_recur_1] ${caller_id_name}(NOT_Giovanni) =~ /Giovanni/ break=on-false
Advanced Condition/Action Rules
break="on-true"
Рассмотрим использование break="on-true"
и break="on-false"
на примере основанных на времени условий.
Вызывается номер 1100, действующая служба поддержки работает с 8-ми до до 22 часов, за исключением пятницы, когда рабочий день с 8-ми до 13 часов. В любое другое время вызов отправляется на голосовую почту.
<extension name="Time-of-day"> <!--Если первоначальное условие ложно, будет выполнен переход к след. расширениям.--> <condition field="destination_number" expression="^1100$" break="on-false"/> <!--on-true прекращает проверку остальных условий, если это истинно.--> <condition wday="6" hour="8-12" break="on-true"> <!--Fri, 8am-12:59pm I don't care if Monday's blue Tuesday's grey and Wednesday too Thursday I don't care about you It's Friday, I'm in love--> <action application="transfer" data="1105 XML default"/> </condition> <condition wday="2-5" hour="8-21" break="on-true"> <!--Monday-Thursday, 8am-9:59pm--> <action application="transfer" data="1105 XML default"/> </condition> <condition> <!--последнее действие поймает все, что не попало в указанное время и отправит на голосовую почту. --> <action application="voicemail" data="default ${domain} 1105"/> </condition> </extension> |
Состояние break="on-true"
прекращает проверку других условий, если его условие истинно.
По умолчанию, если не указано другое, подразумевается поведение break="on-false"
.
break="never"
Состояние break="never"
указывает всегда рассматривать последующие условия данного расширения, даже если условие ложно. Это может быть использовано для установки меток в процессе обслуживания вызова. В примере назначается переменная begins_with_one
, если вызываемый номер начинается с «1».
<extension name="break-demo"> <condition field="destination_number" expression="^1(\d+)$" break="never"> <action application="set" data="begins_with_one=true"/> </condition> <condition field="destination_number" expression="^(\d+)$"> ...other actions that may query begins_with_one... </condition> </extension> |
Asterisk Pattern Matching
В дополнение к PCRE Freeswitch также поддерживает паттерны Asterisk.
Выражения должны начинаться с нижнего подчеркивания _
.
См. также: https://freeswitch.org/confluence/display/FREESWITCH/mod_dialplan_asterisk
Звездочка *
должна экранироваться \
(смотрите в примере).
<extension name="US-Domestic"> <condition field="destination_number" expression="_(NXXXXXXXXX)"> <action application="bridge" data="sofia/internal/$1@example.com"/> </condition> </extension> <extension name="star-code-using-escape"> <condition field="destination_number" expression="_(\*XX)(.)"> <action application="log" data="ERR captured $1 ~~~ $2"/> <action application="answer"/> <action application="playback" data="tone_stream://path=${base_dir}/conf/tetris.ttml;loops=10"/> </condition> </extension> |