Оптимизируем листинг диалплана Asterisk при помощи MySQL

Большинство компаний сейчас имеют IP-телефонию, построенную на базе Asterisk(*). Недавно столкнулся со следующей, на первый взгляд, банальной задачей: имеется около 50 человек сотрудников, у каждого из них есть внутренний (добавочный) номер и корпоративный рабочий. Надо чтобы сотрудник был постоянно на связи, так как в офисе не все и не всегда находятся, а если не дозвониться клиент — будет беда. Первое, что приходит в голову — диалплан следующего вида:

exten => 3333,1,Dial(SIP/${EXTEN},20,tT); вызываем добавочный
exten => 3333,2,Dial(SIP/trunk/3809631234567,60,tT); если не ответ — набираем на мобильный.

Вроде все просто и красиво. НО! Это мы описали только одного сотрудника, а их 50! А еще надо каждый разговор записать, например. Листинг уже разрастается до неприличных масштабов. И не только листинг, но и количество ошибок, что можно наделать в процессе составления диалплана. Первое, что мне пришло в голову — старый, добрый MySQL. Что мы можем тут реализовать? Все просто, забиваем базу сотрудников с их добавочными и мобильными номерами и, подставляя их в переменные, звоним.

Звездочку я поднимал из дистрибутива AsteriskNOW, который с уже поднятым мускулом и всем прочим. Неплохо бы создать базу и табличку для наших абонентов. У меня база называется aster_num и таблица в ней — numbers.

describe numbers;
+---------------+----------------+------+-----+---------+------------------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-----------------+------+-----+---------+-----------------------+
| id | int(6) | NO | PRI | NULL | auto_increment |
| asterisk | varchar(20) | NO | | NULL | |
| mobile | varchar(20) | NO | | NULL | |
| first_name | varchar(20) | NO | | NULL | |
| last_name | varchar(20 ) | NO | | NULL | |
| location | varchar(20) | NO | | NULL | |
+---------------+-----------------+-------+-----+---------+---------------------+

Немного о колонках нашей таблицы:

id — уникальный идентификатор сотрудника
asterisk — добавочные номера
mobile — мобильные номера
first_name — имя сотрудника
last_name — фамилия сотрудника
location — адрес филиала офиса

* соединяется с MySQL через ODBC коннектор, параметры которого описываются в файле /etc/odbcinst.ini.

Опишем в нем наше подключение:
[aster_num]
driver=MySQL
server=localhost
user=xxx
password=xxx
database=aster_num
Port=3306

Настроим подключение * к нашей базе.

/etc/asterisk/res_odbc.conf
[aster_num]
enabled=>yes
dsn=>aster_num
username=>xxx
password=>xxx
pooling=>no
limit=>1
pre-connect=>yes

После перезагрузки проверяем наше подключение. Команда * odbc show all должна нам показать примерно следующее:

Name: aster_num
DSN: aster_num
Last connection attempt: 1970-01-01 03:00:00
Pooled: No
Connected: Yes

Итого, у нас все красиво работает! Ура! Осталось совсем не много: заполнить таблицу и написать диалплан. Предположим, что у нас есть сотрудник Иван Иванов, с добавочным 3333 и мобильным 380631234567. И сотрудник Петр Петров, с добавочным 3444 и мобильным 380979876543. Внесем их в нашу таблицу numders.

numders
+----+----------+-------------------+--------------+----------------+--------------+
| id | asterisk | mobile | first_name | last_name | location |
+----+----------+-------------------+--------------+----------------+--------------+
| 1 | 3333 | 380631234567 | Ivan | Ivanov | Kiev |
| 2 | 3444 | 380979876543 | Petr | Petrov | Kiev |


Набросаем диалплан:

extensions.conf
exten => _3XXX,1,Dial(SIP/${EXTEN},20,tT)
exten => _3XXX,2,MySQL(Connect connid localhost xxx xxx aster_num)
exten => _3XXX,3,MySQL(Query resultid ${connid} SELECT mobile FROM numbers WHERE asterisk=${EXTEN})
exten => _3XXX,4,MySQL(Fetch fetchid ${resultid} mob_num)
exten => _3XXX,5,Dial(SIP/trunk/${mob_num},60,tT)
exten => _3XXX,6,MYSQL(Clear ${resultid})
exten => _3XXX,7,MYSQL(Disconnect ${connid})

Немного поясню по пунктам, итак:
exten => _3XXX,1,Dial(SIP/${EXTEN},20,tT) — звоним на добавочный, который записан в переменную ${EXTEN}, в течении 20 сек, с возможностью перевода звонка.
exten => _3XXX,2,MySQL(Connect connid localhost xxx xxx aster_num) — инициализируем подключение к базе сотрудников
exten => _3XXX,3,MySQL(Query resultid ${connid} SELECT mobile FROM numbers WHERE asterisk=${EXTEN}) — элементарный запрос, для поиска мобильного номера сотрудника
exten => _3XXX,4,MySQL(Fetch fetchid ${resultid} mob_num) — подставляем мобильный номер в переменную
exten => _3XXX,5,Dial(SIP/trunk/${mob_num},60,tT) — и звоним на него!
exten => _3XXX,6,MYSQL(Clear ${resultid}) — очищаем переменную
exten => _3XXX,7,MYSQL(Disconnect ${connid}) — закрываем подключение к базе.

Таким образом, всего семь строк могут описать звонки с переадресацией и переводом номера для какого угодно количество сотрудников.

Согласитесь, что будет не слишком удобно для добавления нового сотрудника в базу открывать мускул и заниматься скучными insert`ами. Для этого я написал простенькую админку, которая прекрасно справляется с этой задачей. Подробное описание ее будет в следующей статье. А пока вот ее скриншот:

image

Надеюсь, кому-то данная публикация поможет. Если возникают предложения, вопросы или проблемы — пишите, не стесняйтесь.
  • +3
  • 11.4k
  • 8
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 8

    +1
    Имхо не совсем корректно юзать ODBC и команду диалплана MYSQL, надо тогда все запросы и писать в рамках ODBC. А может и вообще вынести всю логику на сторону AGI, что крайне котирует уважаемый antirek :)

    PS Ждем следующей статьи с кодом админки:)
      0
      Можно и через AGI обрабатывать. Как кому нравиться) Для меня это был первый опыт такого рода оптимизации, и я остался всем доволен. + ODBC вшит в дистрибутив, и проблем с ним нет. А про админку напишу на этой неделе)
        +1
        MYSQL (приложение диалплана) не использует odbc настройки астериска, по идее должно работать и без настроек /etc/odbcinst.ini и res_odbc.conf.

        И да, я бы сделал логику приложения на стороне AGI: )

          0
          А этот момент я проверял. Работает, но криво и через раз)
            0
            А потому MYSQL и не рекомендуют, посмотрите в сторону func_odbc.conf (у вас настройки есть, запросы есть, только настроить осталось) — диалплан станет чище.
              +1
              Чтоб долго не мучаться, вот пример, я тут вытаскиваю имя из базы по CALLERID:

              В файле /etc/odbcinst.ini прописываем пути для драйверов (это для убунты, для центоса разница в путях к библиотекам будет):
              [MySQL]
              Description = MySQL driver
              Driver = /usr/lib/x86_64-linux-gnu/odbc/libmyodbc.so
              Setup = /usr/lib/x86_64-linux-gnu/odbc/libodbcmyS.so
              CPTimeout =
              CPReuse =

              ;;Centos, разница в названии библиотек и путях
              [MySQL]
              Description = ODBC for MySQL
              Driver = /usr/lib/libmyodbc3.so
              Setup = /usr/lib/libodbcmyS.so
              FileUsage = 1

              В файле /etc/odbc.ini описываем параметры odbc-подключения:

              [asterisk-barrier]
              Driver = MySQL
              Description = Connector/ODBC 3.51 Driver DSN
              Server = localhost
              Port = 3306
              User = root
              Password = VeryStrongPassword
              Database = barrier
              Socket = /var/run/mysqld/mysqld.sock
              Charset = utf8

              В файле /etc/asterisk/res_odbc.conf описываем параметры odbc-подключения:

              [asterisk-barrier]
              enabled => yes
              dsn => asterisk-barrier
              username => root
              password => VeryStrongPassword
              pooling => no
              limit => 1
              pre-connect => yes

              В func_odbc.conf пишем функцию, которая будет искать в MySQL номер вызывающего абонента и возвращать нам его имя

              [MOBILE]
              dsn=asterisk-barrier
              readsql=SELECT name FROM numbers WHERE phone = '${CALLER}'

              и в диалплане что-то типа:

              exten => s,1,Set(CALLER=${CALLERID(num)})
              same => n,Set(result=${ODBC_MOBILE()}) ;;looking for phone number is mysql, return id
              same => n,Set(foo=${ISNULL(${result})}) ;;isnull — is there a number in mysql? 1 or 0
              same => n,GotoIf($["${foo}" = «0»]?true:false)
        0
        а разве после exten => _3XXX,5,Dial(SIP/trunk/${mob_num},60,tT) будет обрыв и потом соединение не очиститься?!
          0
          Можно было бы кинуть код хотя бы в комменты, раз не стали обещанный пост делать.
          Спасибо.

          Only users with full accounts can post comments. Log in, please.