В Астериске, всем известно, вся маршрутизация делается в диалплане. Но если у оператора много направлений и цена на каждое из них различна, то в диалплане получаются портянки на несколько страниц. Решения разные: кто-то разбивает по разным файлам диалплана, использует макросы, кто-то подключает к работе БД, кто-то выносит на отдельный сервис.
Я хочу поделиться своим решением: вынести поиск оператора с наименьшей стоимостью заданного направления в стороннее приложение на node.js, с которым Астериск взаимодействует посредством AGI.
Задача
Получить простое и быстрое решение для определения оператора, у которого наименьшая стоимость минуты звонка, которое также быстро устанавливается и настраивается.
С одной стороны с приложением должен взаимодействовать Астериск, передавая направление звонка и запрашивая оператора с наименьшей стоимостью. С другой стороны через веб-интерфейс с приложением взаимодействует пользователь, который добавляет операторов связи, направления и их стоимость.
Схема
LCR Finder
Подробная установка в описании к проекту на гитхабе. Но мы воспользуемся заготовкой приложения lcr-finder-app (клонируем, устанавливаем зависимости и запускаем приложение).
Установленное приложение открывает два порта для соединений, одно для Астериска — запросов по AGI, другое для веб-интерфейса.
Затем настроить Астериск в файле extensions.conf достаточно выполнить запрос в AGI и сделать вызов по результату.
exten=>_X.,1,AGI(agi://localhost:3000)
exten=>_X.,n,Dial(SIP/${LCR_RESULT}/${EXTEN})
Также после запроса в AGI к LCR Finder'у устанавливаются переменные LCR_STATUS, LCR_RESULT, LCR_SEQUENCE. LCR_STATUS — FAILED, SUCCESS в зависимости от результата поиска, LCR_RESULT — имя оператора с наименьшей стоимостью, LCR_SEQUENCE — список всех операторов через запятую, отсортированных в порядке возрастания стоимости. LCR_SEQUENCE позволяет реализовать failover, если оператор с наименьшей стоимостью не пропускает вызов, то можно взять следующего.
В веб-интерфейсе, который на angular.js быстро сверстал мой коллега Анатолий, все достаточно лаконично: добавляем оператора, добавляем к нему направления и стоимость. Во вкладке поиска можно проверить стоимость направление у операторов.
Вопрос к астерискерам: нужно ли развивать эту систему? Стали бы вы пользоваться ей в своих инсталляциях с Астериском. Сейчас здесь нет загрузки Excel файлов с направлениями (я сначала командой в mongodb загружаю направления, т.к. у меня есть небольшой скрипт для этого, а потом в веб-интерфейсе я или заказчик меняем цены по необходимости). Есть еще задумка с весом оператора, т.к. иногда цена не единственный параметр влияющий на выбор оператора.
Есть ли подобные системы? Конечно, да. Например, знаю, что некоторые используют для A2Billing для LCR, еще есть проект LCDial.sh (не знаю, кто-нибудь им пользуется), кто-то использует такие скрипты.
Надеюсь на конструктивную критику и предложения по улучшению. Думаю, что поможет кому-нибудь сэкономить дополнительные средства для развития в наше непростое время.
P.S. Небольшое видео по установке lcr-finder'а
Комментарии (10)
antivoland
29.05.2015 10:46+1За статью об реализации такой возможности в астериск(хотя и не нативно) — спасибо.
Не рекламы ради…
Мы уже давно пользуемся freeswitch с модулем mod_lcr.antirek Автор
29.05.2015 12:43вот и меня мучает вопрос: почему такой простой функционал не реализован среди стандартных модулей астериска?
freeswitch после астериска вообще песня: )
f1045
29.05.2015 15:17+1Хочется какой-то способ временно выключать звонки через какого-то оператора. Может быть действительно через задание весов, но чтобы был способ управлять этим не только через вебинтерфейс, но и через cli/agi
(например для ситуаций, когда у оператора авария, но звонки он не отбивает, а принимает, просто дальше они не проходят. Или для тарифных планов с каким-то количеством включённых бесплатных минут в день\месяц, чтобы выбрать их, а потом через этот пир по возможности не звонить)antirek Автор
29.05.2015 17:09ок, спасибо за комментарий по теме развития lcr finder'а.
при аварии на стороне оператора, наверное, таки удобнее веб-интерфейс: зашел, выключил кнопкой, позвонил оператору, выяснил время устранения, затем позже зашел опять, включил, проверил звонком.
вот с тарифными планами интереснее: надо учитывать сколько минут проговорил уже, т.е. или дополнительный запрос в agi делать или cdr анализировать, получается биллинг: )
про включение/выключение через cli/agi не понял: делать выключение оператора из команды консоли или по звонку?
f1045
29.05.2015 19:21+1Ну вот да, тащить внутрь LCR-логики статистику по звонкам — наверное излишне. Я это могу и сам в диалплане или где-то снаружи посчитать по CDR, просто чтобы были ручки для выключения\включения пиров в LCR\задания весов. Из консоли, или передавая какие-то параметры в AGI
antirek Автор
01.06.2015 08:06Подумал, что если добавить ручки для включения операторов в веб-интерфейс, то поскольку там используется angular, который будет дергать определенные url и получать результат в json, то эти же запросы могут быть доступны и для сторонних приложений.
Еще можно просто передавать список требуемых операторов в параметрах AGI запроса и получать сравнение только по ним.
antivoland
29.05.2015 17:31+1или анализ параметров при звонках на направления (средняя длительность, количество не ответов и тд) с апдейтом направления для выставления «веса».
На это все навесить уведомление админа о том что направление косячное и в итоге чтото будет похоже на VoIP Studio для Mera по функционалу.
BoDRbI
Спасибо за статью, интересно было прочитать. Возник вопрос, а почему Вы использовали Node.js как промежуточное звено, а не прямое обращение в Mongo из AGI скрипта?
antirek Автор
Немного не понял вопроса. Здесь нет как такового AGI-скрипта, AGI-запрос идет сразу на AGI-сервер (AGI(agi://localhost:3000)), который написан на Javascript'е для выполнения на node.js. AGI-сервер при запуске также подключается к mongodb и работает в режиме ожидания запросов от астериска. Пришел запрос из диалплана — работает сценарий — взять номер, сделать получить направления операторов из БД, найти подходящее, вернуть статусы в диалплан астериска.
Или вопрос был: а зачем этот Node.js здесь вообще, можно написать простой AGI-скрипт, который будет работать также?
BoDRbI
Спасибо, я понял Вас. Я подумал, что из диалплана происходит обращение к AGI-скрипту, который в свою очередь обращается к сервису на Node.js.