gifts2017

Asterisk без внешних компонент?

Опубликовал Олег Ризванов (oleg.rizvanov) в раздел Оборудование - Телефония, SIP

Да, не вопрос! Причем, это делается просто до безобразия! И сейчас, мы с этим  безобразием разберемся. К тому же, у безобразия есть нюансы. Заодно, разберемся с особенностями AMI поверх HTTP.

Будет много текста, да еще и без картинок. Заранее благодарен тем, кто дочитает статью до конца. Постараюсь как минимум не быть нудным :-)

 

Раздел для тех, кто не в теме.

 

Кто уже читал мои предыдущие статьи и знает про AMI (Asterisk Manager Interface) и AJAM, может смело пропустить этот раздел.

AMI – это интерфейс управления Asterisk-ом. Но, подключения к AMI, как и девушки, бывают разные. Два основных:

  1. AMI поверх TCP, который часто называют просто AMI
  2. AMI поверх HTTP, его еще называют AJAM (Asynchronous Javascript Asterisk Manager). Хотя, особой асинхронности я там не увидел.

Если объяснять на пальцах, то разница между 1 и 2, как между толстым и веб-клиентом. Ссылка для тех, кто-то хочет накуриться правильных английских мануалов.

Внешняя компонента ROM-Asterisk может использовать оба способа подключения.
Внешняя компонента от МИКО использует только AJAM.
Но нам, они пока не нужны – мы будем подключаться без них.

 

Настройка AJAM на стороне Asterisk

 

Ребята из МИКО написали хорошую статью о том, как выполнить настройку AJAM в Asterisk. Вдаваться в детали настройки мы не будем, это больше для админа, дайте ему ссылку, пусть настраивает.

 

Кодировщики AJAM

 

Что еще нам нужно знать про AJAM? В нем есть разные типы кодировщиков ответов:

  1. rawman – самый простой, которым мы и будем пользоваться
  2. arawman – тоже самое, что и rawman, плюс использование более навороченной HTTP-digest аутентификации с MD5-хешами
  3. mxml – ответы сервера кодируются в XML
  4. manager – кодирует ответы в простые HTML-формы. Этот кодировщик годится разве что на побаловаться вначале

Схема работы с AJAM

 

Те, кто уже работал с HTTP-сервером, этот раздел могут пропустить.
Важно понимать, что мы работаем с HTTP-сервером. Понятно, что сразу после получения нами HTTP-ответа, сервер разорвет соединение.

Схема будет такой: Connect -> Запрос -> Ответ -> Disconnect

Если хочется еще что-то спросить у Asterisk-а, тогда добро пожаловать в новую итерацию. Это вам не AMI поверх TCP, когда можно 1 раз «зацепиться» за сервер и просто слушать события.

 

Алгоритм наших действий

 

Не менее важно понимать сам алгоритм наших действий. По шагам:

  1. Устанавливаем HTTP-соединение
  2. Авторизуемся. При удачной авторизации, сервер вернет нам Cookie, который мы прихраним для использования в следующем HTTP-запросе
  3. Выполняем нужный нам HTTP-запрос, обновляем Cookie.

Реализация

 

Считаем, что админ уже все настроил и можно приступать.
Все, что нам нужно – это HTTPСоединение и ровные руки, чтобы отправлять ровные запросы.

Код работы с Asterisk настолько тривиальный, что его нет смысла здесь приводить. Все сводится к элементарной отправке и чтению HTTP-запросов. Не верите? Смотрите сами:

Организация соединения:

Соединение=Новый HTTPСоединение(IP,Port,,,,Таймаут,);

Отправка и чтение запроса:

ТекстКоманды="/asterisk/rawman?action=…бла-бла-бла";
Запрос=Новый HTTPЗапрос();
Запрос.АдресРесурса=ТекстКоманды;
Ответ=Соединение.Получить(Запрос);

Это все :)

 

Ложка дегтя

 

Когда мы сами являемся источником события, то все вроде бы как хорошо. А вот, когда мы являемся потребителями и хотим просто слушать, то не все так гладко.

Перефразируя мем «нельзя просто так взять и получать события по AJAM». При работе через AJAM нам нужно будет периодически задалбывать HTTP-сервер запросами типа «Сервер, там для меня случайно нет событий?».

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

Именно для такого случая, придумали AMI-команду WaitEvent. Она делает следующую вещь - говорит Asterisk-у: «Мол, я тут событие жду. Не разрывай пож-та соединение пока оно не придет. Я готов ждать максимум 30 секунд». Asterisk конечно же так и поступит.

Но, все это время, пока мы ждем событие, наш HTTP-запрос будет находиться в «висячем» состоянии и клиентское окно 1С будет выглядеть зависшим.

  1. Пользователю, независимо от пола, «висячее» состояние вряд ли понравится
  2. Сервер тратит свои ресурсы на поддержание открытой сессии

Вы спросите, а может делать частые HTTP-запросы, допустим каждые 10 секунд, с таймаутом ожидания 10 секунд?
Может быть… Я же не знаю вашей нагрузки на Asterisk и на 1С.
ИМХО, здесь важно найти оптимальный баланс - и сервер не задолбать, и не пропустить важное событие AMI.

 

И что с этим делать?

 

Думаю, нужно подбирать решение по конкретной ситуации. Обращайтесь – помогу, если смогу.

В качестве абстрактных рекомендаций, могу сказать следующее:

  1. Ищите, тестируйте и найдете. Весь инструмент во вложенной к статье обработке. Поиграйтесь с частотой запросов и с таймаутом ответа.
  2. Пофильтруйте события – хотя бы уберите лишние классы событий. Об этом написано в других моих статьях.

Если пользователь использует толстый клиент, то скорее всего, он сидит внутри сети. Тогда нечего заморачиваться, можно использовать обычный AMI через TCP. Подключаем этого пользователя через ROM-Asterisk и пусть себе работает.

Если пользователь использует тонкий клиент и сидит внутри сети, тогда тоже самое – AMI поверх TCP и ROM-Asterisk. Кстати, тонкому клиенту удаленному, но с хорошим каналом, это тоже подойдет.

Если пользователь использует веб-клиент или же тонкий клиент на нестабильном канале, тогда однозначно AJAM.

 

Небольшой хак

 

Если у пользователя НЕ веб-клиент, но вы хотите использовать именно AJAM, а не AMI, тогда могу вам дать хорошую подсказку, как уйти от «висячего» HTTP-запроса.

Вместо объекта HTTPСоединение можно использовать соединение ROM-Asterisk, а вместо объекта HTTPЗапрос использовать метод ВыполнитьКоманду. В этом случае, подмерзания не будет – ответ придет асинхронно, как внешнее событие. Вы отдали команду и забыли, когда придет ответ – Asterisk вам сам скажет.
Выложу реализацию этого хозяйства в отдельной статье.

 

Выводим выводы

 

Подключаться к AJAM без внешних компонент можно и это совершенно не сложно. Хотя, с точки зрения производительности, это не всегда оптимально. Иногда вместо HTTP-соединения, правильнее использовать соединение по TCP. Может в будущем в 1С появится объект TCPСоединение, а пока для этого нужны внешние компоненты.

Использовать AJAM лучше там, где это действительно нужно. Если можно использовать AMI поверх TCP – используйте, с ним проще. На нем можно делать всякие потрясающие штуки. Зато, AJAM – отличное решение для веб-клиента или плохих каналов.

К статье приложена внешняя обработка AJAM, которая будет работать как в режиме управляемого приложения, так и в обычном режиме.

Успешной вам разработки!

Скачать файлы

Наименование Файл Версия Размер
AJAM 115
.epf 12,88Kb
03.05.13
115
.epf 12,88Kb Скачать

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Антон Стеклов (asved.ru) 08.05.13 09:22
А WaitEvent можно отправить в фоновое задание.
2. Александр Лапшин (zfilin) 08.05.13 12:13
Хотел тебе ссылку отправить, мол, смотри какая крутецкая статья по Asterisk. А это ты ее и написал. =)))
3. Олег Ризванов (oleg.rizvanov) 08.05.13 13:16
(1) asved.ru,
Наверное можно. Всегда считал, что фоновое задание выполняется на стороне сервера, а нам вроде как надо клиенту результат отдать...
Не до конца понимаю, как фоновое задание использовать для данной задачи? Приведете пример?
4. Олег Ризванов (oleg.rizvanov) 08.05.13 13:16
(2) zfilin,
Привет, Саша. Стараюсь для сообщества :)
5. Антон Стеклов (asved.ru) 08.05.13 13:35
(3) oleg.rizvanov, честно говоря, разбираться некогда, суть в том, что этим мы избежим "зависания" на стороне пользователя. Правда, инициализировать проверку результата все равно придется со стороны клиента, через ОбработкаОжидания(), к примеру. Но это уже в рамках 1С, что, я полагаю, существенный плюс.
6. Олег Ризванов (oleg.rizvanov) 08.05.13 13:51
(5) asved.ru,
А в именно чем плюс? Какая разница кого периодически опрашивать HTTP-сервер или 1С-сервер?
Тогда уже лучше не париться с родным объектом HTTPСоединение, а использовать XMLHTTPRequest
7. Петр Вел (shmellevich) 10.05.13 13:19
Если пользоваться
Ответ=Соединение.Получить(Запрос);
для получения ответа от сервера, то нужно автору уточнить, что версия платформы должна быть не ниже 8.2.18, ибо только в этом релизе уже есть HTTPОтвет.
8. Олег Ризванов (oleg.rizvanov) 10.05.13 14:00
(7) shmellevich,
Да, действительно, этот момент я как-то упустил.
Спасибо за важное уточнение.
9. Петр Вел (shmellevich) 10.05.13 14:25
(8) oleg.rizvanov,
Пожалуйста, конструкция сразу глаз начала резать ;)
К хорошему быстро привыкаешь, тестил 8.3, да так увлекся, что начал теряться, где что работает )))
10. oleg (oleg1979) 01.08.13 12:45
Подскажите пожалуйста, можно ли в 1С 8.2 при дозвонке на какой либо номер через Asterisk определять статусы звонков "занято", "нет ответа", "трубка поднята"?
11. Олег Ризванов (oleg.rizvanov) 01.08.13 13:34
(10) oleg1979,
Можно. Поднимите ветку с этим вопросом в форуме Simplit - вам ответят
12. Fred (Aspirant) 30.01.14 18:35
когда будет кросс платформенное решение ? Очень хочется на линукс пересесть..
13. Fred (Aspirant) 04.02.14 14:33
еще какой командой можно выцепить имя файла записи разговора?
14. Fred (Aspirant) 13.02.14 12:12
в веб клиенте не получится? Там не работает HTTPСоединение
15. Олег Ризванов (oleg.rizvanov) 13.02.14 19:23
(14) Aspirant,
Для веб-клиента этот объект недоступен. Попробуйте обойти через сервер.
16. г. Казань Рустем Гумеров (Rustig) 14.06.16 16:23
(0) подскажите, пож-та, скачал вашу обработку, при указании айпи-адреса, логина и пароля, не логинится сервер. выдается ошибка
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
<hr />
<address>Asterisk Server</address>
</body></html>