Короткие номера и MySQL 25.04.2011

Следующий этап – предварительно проработать возможность набора по коротким номерам. Существует несколько вариантов (кстати, это вообще свойственно астериску) выполнить такой фокус.

Жесткая привязка номера

Тут все просто. Добавляем в диалплан правило набора жесткого номера и приписываем длинный номер.

В качестве примера – короткий номер 123 будет набирать длинный (хотя, в качестве примера я взял внутренний 1261)

[internal_phones]

exten => 123,1,NoOp(Redirection 123)
exten => 123,n,Dial(SIP/1261)
exten => 123,n,Hangup()

Как говориться – дешево и сердито :)

Проблема наступает тогда, когда необходимо таких переадресаций сделать, скажем, 100. Соответственно, у нас добавится 300 строк в диалплан и редактировать их станет кошмаром. Более того, очень сложно будет, например, вписать одну дополнительную строку в каждый блок переадресации.

В общем, этот вариант хорош тогда, когда количество номеров переадресаций невелико. Ну и, пожалуй, в качестве плюса можно указать то, что этот вариант немного более устойчив от вшених изменений, чем дальнейшие, т.к. все жестко прописано в файле.

Динамическая жесткая привязка

Следующей моей идеей было:

  • вынести переадресации в отдельный файл, чтобы не загаживать основной диалплан (файл, разумеется, подключить при помощи include);
  • сам файл формировать программно на основании списка дополнительных номеров (эту задачу можно было бы запускать по Cron).

Сразу скажу – почему этот вариант я даже не стал пробовать (тоже в виде красивого списка :)

  • пришлось бы либо часто перегружать диалплан, либо смириться с добавлением новых номеров, скажем, раз в день;
  • "внутри" астериска диалплан был бы слишком большой, что усложняло бы отладку, да и увеличивало нагрузку;
  • нельзя было бы менять этот файл через сам астериск (например, набрав комбинацию *123*1262* на телефоне – установить новую переадресацию).

Из плюсов я бы отметил наглядность редактирования, да пожалуй и все.

Использование Asterisk DB

Так же не стал пробовать.

Здесь из плюсов:

  • возможность редактирования с телефона;
  • простой диалплан без необходимости перезагрузок.

Из минусов – нет наглядности. Т.е., сложно увидеть глазами – куда переадресовывается номер 123 или какие короткие номера сопоставлены номеру 1261.

Использование MySQL

Как вы уже догадались, именно этот вариант я и выбрал, т.к. он состоит из одних плюсов:

  • можно редактировать как из астериска, так и из любого средства работы с MySQL, плюс ко всему всегда можно дописать веб-интерфейс;
  • можно формировать список из внешних источников, делать запросы и тд;
  • сам диалплан достаточно простой.

В общем, это мой случай :)

Временно сформируем задачу так: все четырехзначные номера, начинающиеся на 6, искать в БД и пробовать набрать через SIP.

Настройка связи с MySQL

Первым делом, я поставил MySQL. Эту часть я здесь расписывать не буду. Напомню только о необходимости добавить его в автозагрузку и создать пользователя для asterisk.

Создаем базу (я назвал ее asterisk) и в ней таблицу с двумя полями:

CREATE TABLE  `asterisk`.`tbl_short_numbers` (
  `short_number` varchar(10) NOT NULL,
  `long_number` varchar(50) NOT NULL,
  PRIMARY KEY  (`short_number`)
)

Соответственно, в поле short_number (оно уникально) храниться короткий номер, а в long_number – номер для переадресации.

Сразу внесем номер для переадресации в тестовых целях (при наборе 6261 набрать 1261):

insert ignore into tbl_short_numbers
(short_number,long_number)
values
('6261','1261')

Мы будем подключаться к MySQL через ODBC. На всякий случай – укажу как поставить ODBC через yum.

yum install -y unixODBC unixODBC-devel libtool-ltdl libtool-ltdl-devel mysql-connector-odbc asterisk18-odbc

В файле /etc/odbcinst.ini раскомментируем (или добавляем):

[MySQL]
Description     = ODBC for MySQL
Driver          = /usr/lib64/libmyodbc3.so
Setup           = /usr/lib64/libodbcmyS.so
FileUsage       = 1

Обратите внимание на пути к библиотекам! У вас они могут быть другими.

В файл /etc/odbc.ini добавляем настройки базы

[asterisk-connector]
Driver=MySQL
database=asterisk
server=localhost
user=asterisk
password=*****

Проверим соединение

[root@asterisk etc]# echo "select 1" | isql -v asterisk-connector
+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> +---------------------+
| 1                   |
+---------------------+
| 1                   |
+---------------------+
SQLRowCount returns 1
1 rows fetched

ODBC настроен. Пришло время подключить все это к астериск.

Создаем файл /etc/asterisk/res_odbc.conf и в нем прописываем (кстати, у меня почему-то не запускалось без прописывания логина и пароля в обоих файлах)

[ENV]
; задаем будущий контекст
[asterisk]
enabled => yes
; odbc имя
dsn => asterisk-connector
; подключаться при старте asterisk
pre-connect => yes
; имя пользователя
username => asterisk
; пароль
password => *****
; пинговать сервер
pooling => yes

Перезапускаем астериск и проверяем подключение

asterisk*CLI> odbc show

ODBC DSN Settings
— ----------------

  Name:   asterisk
  DSN:    asterisk-connector
    Last connection attempt: 1970-01-01 03:00:00
  Pooled: Yes
  Limit:  5
  Connections in use: 1
    - Connection 1: connected

Использование MySQL в диалплане

Первым делом – определяем функцию, которая будет использоваться для получения номера. Для этого – создаем файл /etc/asterisk/func_odbc.conf и в нем прописываем функцию:

[GET_LONG_NUMBER]
; задаем DSN из res_odbc.conf
dsn=asterisk
; задаем SQL запрос к базе
; с первым аргументом функции
readsql=SELECT long_number FROM tbl_short_numbers WHERE short_number = '${ARG1}'

В диалплане эта функция будет имеет префикс ODBC_.

Теперь настраиваем диалплан

[internal_phones]

exten => _6XXX,1,NoOp(prefix 6 dialed ${EXTEN})
; задаем переменную для хранения номера
; с именем NUMBER_TO_DIAL
; из базы
exten => _6XXX,n,Set(NUMBER_TO_DIAL=${ODBC_GET_LONG_NUMBER(${EXTEN})});
; если мы получили пустой номер - сообщаем,
; что номер не существует
exten => _6XXX,n,GotoIf($["${NUMBER_TO_DIAL}" = ""]?number_exists)
; иначе - набираем.
; в тестовых целях - исключительно через SIP
exten => _6XXX,n,Dial(SIP/${NUMBER_TO_DIAL})
exten => _6XXX,n,Hangup();

; обработка ошибок
; неверный номер
exten => _6XXX,n(number_exists),Playback(rittal/number_is_wrong)
exten => _6XXX,n(number_exists),Hangup()

Соответственно, при наборе короткого номера, присутствующего в базе, будет набран длинный номер через SIP, а если короткий номер отсутствует – будет выдано сообщение о том, что номер не существует.