- PVSM.RU - https://www.pvsm.ru -
В начале времен единственным "поставщиком" функционала Asterisk были модули, многие из которых расширяли арсенал приложений и функций плана набора.
Тогда, в начале времен, все эти команды и функции далеко опережали свое время, и благодаря им Asterisk "уделывал" по функционалу многие коммерческие продукты.
Если возникала какая-нибудь необходимость в выходе за пределы имеющихся приложений и функций, можно было написать свой собственный модуль на языке С, и это был единственный способ расширения функционала и выхода из имеющейся "клетки", какой бы просторной она ни была.
Но разработку модуля Астериск на языке С сложно назвать тревиальной задачей. Это весьма тернистый путь, к тому же весьма рискованный, ведь критическая ошибка в своем модуле запросто приводила к полному падению Asterisk в core.
Нужны были более "мягкие" и простые способы для расширения функций и интеграции с другими системами.
Так появились интерфейсы AGI и AMI.
Asterisk Gateway Interface (AGI) — это синхронный интерфейс выполнения диалплана, архитектурно "слизанный" с CGI. Команда диалплана AGI запускала процесс, и использовала стандартный ввод и вывод для получения команд и передачи результатов. При помощи AGI можно решать задачи интеграции с внешними системами, например, можно отправиться в корпоративную базу данных и найти имя звонящего клиента по его номеру.
По сути, AGI предоставлял способ написать план набора Asterisk не в формате extensions.conf, а на своем языке программирования, используя поставляемые модулями команды и функции, вокруг которых строится своя бизнес-логика.
Asterisk Manager Interface (AMI) — это асинхронный (событийный) интерфейс, позволяющий контролировать внутреннее состояние объектов в Asterisk, и получать информацию о происходящих событиях. Если AGI архитектурно напоминает CGI интерфейс, то AMI сессия похожа на телнет-сессию, в рамках которой стороннее приложение подключается по TCP/IP к AMI порту Asterisk, и может отправлять свои команды, ответ на которые приходит через некоторое время в виде события-ответа. Помимо ответов на команды в AMI соединение "валятся" всевозможные события, происходящие в Asterisk, и дело клиента определить, относятся они к нему или их можно просто игнорировать.
Про AGI можно сказать, что это call execution механизм, а про AMI — что это call control механизм. Чаще всего для построения своего телекоммуникационного приложения необходимо использовать сразу AGI и AMI вместе. Происходит "размазывание" бизнес логики по разным приложениям, что затрудняет его понимание и дальнейшее сопровождение и развитие.
Помимо этого, существует еще несколько ограничений:
В результате, чтобы вырваться за рамки существующих ограничений команд и функций, надо и писать свой С-модуль, реализующий низкоуровневый телефонный примитив, и интегрироваться с внешними системами при помощи AGI & AMI.
Так было до появления Asterisk REST Interface.
Основные концепции ARI:
"Три кита" ARI:
Пример диалплана, передающего управление в Stais:
exten => _X.,1,Stasis(myapp,arg1,arg2)
exten => _X.,n,NoOp(Left Stasis)
ARI имеет некоторые ограничения
Рассмотрим категории операций, доступных в ARI:
И остановимся на каждой категории подробнее.
Полный список возможных операций смотрите на wiki asterisk — https://wiki.asterisk.org/wiki/display/AST/Asterisk+13+ARI [1]
Приведу частичный список событий, которые доступны на веб-сокете подключенного приложения:
Ну и в заключение приведу пример оригинации вызова при помощи Python ARI библиотеки.
В этом примере делается оригинация по указанному пиру, и возвращается cause code:
import ari
import gevent
from gevent.event import Event
from gevent.monkey import patch_all; patch_all()
ari_client = ari.connect(
conf['pbx_ari_url'],
conf['pbx_ari_user'],
conf['pbx_ari_password']
)
def originate_to_ari(endpoint='', number='', app='', variables={},
callerid='', timeout=60):
evt = Event() # Wait flag for origination
result = {}
channel = ari_client.channels.originate(
endpoint=endpoint,
app='barrier',
appArgs=app,
callerId=callerid,
timeout=timeout,
variables={'variables': variables},
)
def destroyed(channel, event):
result['status'] = 'success'
result['message'] = '%s (%s)' % (
event.get('cause_txt'),
event.get('cause'))
evt.set()
channel.on_event('ChannelDestroyed', destroyed)
# Wait until we get origination result
evt.wait()
return result
P.S. Написано по материалам выступления автора на Asterconf 2016.
Автор: litnimax
Источник [3]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/razrabotka/181297
Ссылки в тексте:
[2] https://wiki.asterisk.org/wiki/display/AST/Asterisk+13+REST+Data+Models: https://wiki.asterisk.org/wiki/display/AST/Asterisk+13+REST+Data+Models
[3] Источник: https://habrahabr.ru/post/308652/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.