Телефонная книга Freeswitch



    Внесение


    Так уж получилось, что Freeswitch – моя маленькая слабость. Да, сейчас в мире более распространен Asterisk, и я его тоже неплохо знаю, но… Чем-то меня привлекает именно Freeswitch. Может набором возможностей, может сверхстабильной работой, может малым потреблением ресурсов и более логичным устройством. А может я просто хипстер от мира IT и желаю быть не как все. Как знать. Мы не психологи, чтобы копаться в потемках человеческой души, поэтому просто примем это как данность и займёмся вещами более практичными. Будем улучшать клиентский сервис. На повестке дня – улучшенная персонализация клиента путём его узнавания.

    Тривия


    Телефонная книга – вещь предельно утилитарная. Присутствует во всех более-менее приличных надстройках над системами IP-телефонии. Позволяет при входящем звонке опознать клиента по номеру телефона. Конечно, мы не отдел продаж, в CRM всех подряд не пишем, но даже сотруднику клиента, который звонит в техническую поддержку со своими проблемами, приятно, когда его сразу узнают. На уровне приложения телефонная книга обычно подключается как плагин, позволяя использовать в качестве источника данных определённое хранилище информации, чаще всего базу данных. Не избежал подобной участи и Freeswitch. В разное время у нас использовалось два варианта телефонной книги:

    • на основе плагина и базы данных SQLite;
    • на основе самописного REST-коннектора на Lua (используется и поныне).

    Я расскажу про реализацию обоих вариантов. У каждого свои преимущества и недостатки.

    Телефонная книга на основе БД проще в устройстве и более стандартна. На официальном сайте Freeswitch есть неплохая дока, по её установке и настройке. Но поскольку на сервере телефонии нет веб-интерфейса (я принципиальный противник веб-интерфейсов к телефонным станциям, но это уже совсем другая история, как-нибудь в следующий раз), то настраивать телефонную книгу может ограниченный круг неограниченных лиц, которых не пугают слова база данных, запрос и иже с ними. А то и консоль, как в моём случае. Вы спросите, а почему не MySQL? Потому что в нём не было необходимости. У нас же не вся Россия в телефонной книге, а всего лишь около 500 контактов. Для этого SQLite оказалось за глаза. Второй сложностью стал сам процесс добавления информации. Добавлять надо в несколько таблиц, учитывать связи и не забывать про дубликаты. У меня до сих пор где-то лежит документ по порядку выполнения запросов на добавление и обновление информации в телефонной книге. Преимущества же очевидны – движок базы данных не требует установки и интеграции дополнительного софта и сам по себе прост, как мычание. Вся телефонная книга лежит в одном файле, легко резервируется и сохраняется. Таблицы внутри предельно простые и понимание их структуры не требует особого мыслительного процесса. Достаточно поднять палку потяжелее и стукнуть соседа слева. Пусть он думает, да.

    Второй вариант телефонной книги был менее тривиален в реализации. Так как мы сейчас активно пытаемся освоить CMDB iTop, появилась идея скрестить телефонную книгу с ней. Благо, стандартный модуль хранения контактов в CMDB наличествует и соответствует. Стандартными методами это сделать не удалось. На помощь пришла Lua, с ней все получилось чисто и аккуратно. Из преимуществ такого подхода можно отметить наличие удобного интерфейса для добавления и редактирования контактов, возможность сохранять любые данные в CMDB, передавать их в телефонную станцию и использовать при маршрутизации звонка (пока не используется, но планируется). Из недостатков — конечно, задержки передачи по сети, зависимость от внешнего сервиса, необходимость программирования и наладки всего этого хозяйства. Но результат того стоит. И, кстати, я не убеждаю вас применять именно такой вариант, просто на его примере хотел бы показать, как можно организовать взаимодействие с внешними сервисами.

    Piece of cake


    По старинной IT-шной традиции пойдём от простого к сложному. Начнём с того, что ляжем на диван и займёмся прокрастинацией. Видите, как просто. Но работа – не волк, с ноги не пнёшь, а потому переводим тело в вертикальное положение и перемещаем поближе к консоли телефонной станции…
    Модуль телефонной книги в Freeswitch называется mod_cidlookup Описание на старом сайте Описание на новом сайте. Для начала надо определиться, стоит ли модуль у нас. Как знать, вдруг просочился незаметно.

    Смотрим наличие модуля в папке модулей.

    ls -la /usr/local/freeswitch/mod/ | grep mod_cidlookup

    Если никаких файлов не оказалось, то у меня для вас плохие новости. Модуль надо собрать или доустановить. Я предпочитаю собирать Freeswitch самостоятельно, поэтому дерево исходников, готовых для сборки, всегда под рукой. Описание того, как собрать модуль для Freeswitch выходит за рамки этой статьи, потому оставим его там и просто примем, что модуль уже лежит в нужной нам папке. Теперь его надо сконфигурировать и подготовить для него данные. Основной конфиг настройки модуля расположен в файле

    /usr/local/freeswitch/conf/autoload_configs/cidlookup.conf.xml
    Минимально рабочий конфиг выглядит примерно так.

    Рабочий конфиг
    <configuration name="cidlookup.conf" description="cidlookup Configuration">
    	<settings>
    		<!-- Кэшируем запрашиваемые данные. -->
    		<param name="cache" value="true"/>
    		<!-- Время жизни записи в кэше - сутки. -->
    		<param name="cache-expire" value="86400"/>
     
    		<!--
    			Строка подключения. Особое внимание на 3 (ТРИ, Карл!) слэша в
    			начале строки. Всё именно так, иначе работать не будет, я
    			проверил. Путь должен быть абсолютным, с относительным база не
    			подключалась.
    		-->
    		<param name="odbc-dsn" value="sqlite:///usr/local/freeswitch/db/phonebook.db"/>
     
    		<!--
    			Запрос на извлечение данных. Принимает подстановочный параметр с
    			номером телефона. Запрос обязательно должен возвращать одну
    			строку.
    		-->
    		<param name="sql" value="
    			SELECT (name || (CASE WHEN comment != '' THEN ' (' || comment || ')' ELSE '' END)) AS name
    				FROM numbers n JOIN phonebook p ON n.pid = p.id
    				WHERE n.number='${caller_id_number}'
    				LIMIT 1
    		"/>
    	</settings>
    </configuration>
    


    Обратите внимание на условное выражение в SELECT. Оно позволяет извлекать из базы компанию клиента и из поля комментария его должность. Если же поле пустое, то возвращается только фамилия и имя, как и положено. В связи с тем, что всегда возвращается только одна строка, дубликаты игнорируются, и возвращается самая ранняя запись из телефонной книги. Поэтому перед добавлением данных надо обязательно проверять, что их нет в базе. Связывание в телефонной книге используется для поддержки нескольких номеров телефонов у одного пользователя.

    Переходим к созданию базы данных для нашей телефонной книги.

    sudo -u freeswitch sqlite3 /usr/local/freeswitch/db/phonebook.db

    -- Создаем необходимые таблицы и индексы.
    -- Контакты.
    CREATE TABLE phonebook (
    	id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE,
    	name VARCHAR (128) NOT NULL,
    	comment VARCHAR (256)
    );
    CREATE INDEX name ON phonebook (name);
     
    -- Номера телефонов.
    CREATE TABLE numbers (
    	id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    	pid INTEGER REFERENCES phonebook (id) ON DELETE CASCADE NOT NULL,
    	NUMBER VARCHAR (32) NOT NULL
    );
    CREATE INDEX NUMBER ON numbers (NUMBER);
     
    -- Добавляем немного данных для тестирования.
    INSERT INTO `phonebook` (`name`, `comment`) VALUES ('Иван Иванов', 'Рога и копыта, менеджер');
    INSERT INTO `numbers` (`pid`, `number`) VALUES (LAST_INSERT_ROWID(), '79152323245');
    INSERT INTO `phonebook` (`name`) VALUES ('Петр Петров');
    INSERT INTO `numbers` (`pid`, `number`) VALUES (LAST_INSERT_ROWID(), '74953462323');
    

    Выходим из консоли SQLite.

    .exit

    Теперь надо загрузить модуль и натравить его на свежесозданную телефонную книгу. Заходим в консоль Freeswitch.

    fs_cli

    Ищем загруженный модуль телефонной книги.

    freeswitch@internal> show modules mod_cidlookup
    
    0 total.
    

    Ага, модуля нет. Пробуем его загрузить.

    freeswitch@internal> load mod_cidlookup
    +OK Reloading XML
    +OK
    
    2016-10-29 14:36:33.890548 [DEBUG] mod_cidlookup.c:122 Connecting to dsn: sqlite:///usr/local/freeswitch/db/phonebook.db
    2016-10-29 14:36:33.890548 [INFO] mod_enum.c:880 ENUM Reloaded
    2016-10-29 14:36:33.890548 [INFO] switch_time.c:1415 Timezone reloaded 1781 definitions
    2016-10-29 14:36:33.890548 [CONSOLE] switch_loadable_module.c:1538 Successfully Loaded [mod_cidlookup]
    2016-10-29 14:36:33.890548 [NOTICE] switch_loadable_module.c:292 Adding Application 'cidlookup'
    2016-10-29 14:36:33.890548 [NOTICE] switch_loadable_module.c:338 Adding API Function 'cidlookup'
    .
    

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

    freeswitch@internal> show modules mod_cidlookup
    type,name,ikey,filename
    api,cidlookup,mod_cidlookup,/usr/local/freeswitch/mod/mod_cidlookup.so
    application,cidlookup,mod_cidlookup,/usr/local/freeswitch/mod/mod_cidlookup.so
    
    2 total.

    Теперь необходимо протестировать работоспособность модуля. Это также можно сделать через консоль, используя API-функцию cidlookup. Смотрим ее синтаксис.

    freeswitch@internal> show api cidlookup
    name,description,syntax,ikey
    cidlookup,cidlookup API,cidlookup status|number [skipurl] [skipcitystate] [verbose],mod_cidlookup
    
    1 total.

    Припоминаем те данные, которые мы добавляли в телефонную книгу и тестируем работу API.

    freeswitch@internal> cidlookup 79152323245
    Иван Иванов (Рога и копыта, менеджер)
    
    freeswitch@internal> cidlookup 74953462323
    Петр Петров

    Как можно видеть, функция возвращает корректные данные контакта из телефонной книги. При этом, если есть комментарий, то он тоже возвращается в скобках. Теперь надо добавить эту функцию в диалплан, чтобы нести свет и радость людям. Так как диалплан у всех устроен по-разному, я покажу только его часть, которая касается телефонной книги и укажу её примерное размещение. У меня она располагается в файле /usr/local/freeswitch/conf/dialplan/public.xml.

    <!-- Активируем поиск по номеру телефона. -->
    <!-- Присваиваем значение по умолчанию для номера телефона. -->
    <extension name="cid_number_cleanup" continue="true">
    	<condition field="caller_id_number" expression="^(\d+)$">
    		<action application="set" data="effective_caller_id_number=$1" inline="true"/>
    	</condition>
    </extension>
     
    <!-- Присваиваем значение по умолчанию для имени контакта. -->
    <extension name="cid_name_cleanup" continue="true">
    	<condition field="caller_id_name" expression="^(\d+)$">
    		<action application="set" data="effective_caller_id_name=$1" inline="true"/>
    	</condition>
    </extension>
     
    <!--
    	Значения по умолчанию оберегают нас от ситуации, когда поиск номера в телефонной книге невозможен,
    	не успевает выполниться, или модуля вообще нет. В этом случае мы просто получим вместо имени контакта
    	его номер.
    -->
     
    <extension name="cid_lookup" continue="true">
    	<condition field="${module_exists(mod_cidlookup)}" expression="true"/>
    	<condition field="caller_id_name" expression="^(\d+)$|^$"/>
    	<condition field="caller_id_number" expression="^(\d+)$">
    		<action application="cidlookup" data="$1"/>
    	</condition>
    </extension>

    Сохраняем файл, выполняем перезагрузку диалплана командой

    fs_cli -x reloadxml

    Если ошибок нет, то можно проверять работу модуля. Вдоволь наигравшись, добавляем модуль в автозагрузку. Это делается в файле /usr/local/freeswitch/conf/autoload_configs/modules.conf.xml. Ищем там строчку

    <load module="mod_cidlookup"/>

    и раскомментируем её. Если же она отсутствует, то просто добавляем её в конец файла.

    Вот и всё, телефонная книга настроена. Но админы не были бы админами, если бы не хотели постоянно что-то улучшить. И поход по этой дороге приводит к следующей части нашего повествования.

    Let's Rock


    Взаимодействие Freeswitch и iTop устроено вполне стандартным способом, через REST-интерфейс, описанный на официальном сайте. В чем же сложность? В том, что напрямую с ним взаимодействовать не получится, надо призывать на помощь силу лебедя плагинов. Изначально планировалось использовать mod_curl, но с ним как-то не заладилось. Было принято решение написать свой небольшой скрипт на Lua и вызывать его через mod_lua. Перво-наперво надо подготовить саму телефонную книгу, то есть тем или иным способом загрузить контакты в iTop. На ваш выбор — источники синхронизации, загрузка CSV или наполнение телефонной книги вручную. Так как у нас тут песочница и много контактов нам не надо, то, давайте, создадим одну организацию и внесём в нее несколько контактов. Для внесения изменений в CMDB вы должны обладать соответствующими правами или быть администратором.

    • Открываем iTop, в боковом меню идём по адресу Администрирование данных → Организации и жмём справа кнопку «Новый…».



    • Заполняем необходимые поля и жмём кнопку «Создать».



    • Если всё сделано правильно, нас перебросит на страницу созданной организации.



    • Теперь в меню переходим по адресу Управление конфигурациями → Контакты → Создать контакт. В открывшемся окне выбираем тип контакта «Персона» и нажимаем «Применить».



    • Откроется окно добавления контакта. Заполните все необходимые поля и нажмите кнопку «Создать». Обратите внимание, что в стандартной установке iTop нет части полей с дополнительными телефонами, они добавлены мной путем редактирования модели, чтобы решить проблему с несколькими телефонами. Редактирование модели выходит за рамки статьи, подробнее с ним можно ознакомиться тут
    .

    • Если вас перебросило на страницу контакта, то всё сделано правильно.


    Похожим образом добавляем ещё несколько контактов. Теперь у нас есть, где искать и можно переходить к настройке телефонной станции. Как я уже говорил, запрашивать будем через REST-интерфейс iTop. Его распечатка и вдумчивое вкуривание вылились в следующий запрос.

    {
    	"operation": "core/get",
    	"class": "Person",
    	"key": "SELECT Person AS P WHERE P.phone = '79101001122' OR P.add_phone = '79101001122' OR P.add_phone_2 = '79101001122' OR P.mobile_phone = '79101001122' OR P.add_mobile_phone = '79101001122'",
    	"output_fields": "friendlyname,org_id_friendlyname,function"
    }

    Попробуем выполнить его при помощи Curl.

    curl -XPOST 'https://<itop_address>/webservices/rest.php?version=1.0' -d 'auth_user=admin&auth_pwd=password&json_data=%7B%22operation%22%3A%22core%2Fget%22%2C%22class%22%3A%22Person%22%2C%22key%22%3A%22SELECT%20Person%20AS%20P%20WHERE%20P.phone%20%3D%20%2779101001122%27%20OR%20P.add_phone%20%3D%20%2779101001122%27%20OR%20P.add_phone_2%20%3D%20%2779101001122%27%20OR%20P.mobile_phone%20%3D%20%2779101001122%27%20OR%20P.add_mobile_phone%20%3D%20%2779101001122%27%22%2C%22output_fields%22%3A%22friendlyname%2Corg_id_friendlyname%2Cfunction%22%7D'

    Как можно заметить, запрос требует аутентификации. Пользователь в iTop должен существовать и обладать необходимыми правами для выполнения запросов.

    В ответ получаем найденного пользователя:

    {
    	"objects": {
    		"Person::486": {
    			"code": 0,
    			"message": "",
    			"class": "Person",
    			"key": "486",
    			"fields": {
    				"friendlyname": "\u0412\u0430\u0441\u0438\u043b\u0438\u0439 \u041f\u0443\u043f\u043a\u0435\u0432\u0438\u0447",
    				"org_id_friendlyname": "\u0420\u043e\u0433\u0430 \u0438 \u043a\u043e\u043f\u044b\u0442\u0430",
    				"function": "\u0421\u0443\u043f\u0435\u0440\u0445\u043e\u043c\u044f\u043a"
    			}
    		}
    	},
    	"code": 0,
    	"message": "Found: 1"
    }

    В более читабельном варианте

    {
    	"objects": {
    		"Person::486": {
    			"code": 0,
    			"message": "",
    			"class": "Person",
    			"key": "486",
    			"fields": {
    				"friendlyname": "Василий Пупкевич",
    				"org_id_friendlyname": "Рога и копыта",
    				"function": "Суперхомяк"
    			}
    		}
    	},
    	"code": 0,
    	"message": "Found: 1"
    }

    Итак, данные принимаются и передаются, пользователи ищутся. Самое время расчехлить любимую IDE и написать что-нибудь вдохновенное. Создаём отдельную папку для скриптов Freeswitch.

    mkdir /usr/local/freeswitch/scripts

    В этой папке создаём подпапку lib, в которой будем хранить общие библиотеки.

    mkdir /usr/local/freeswitch/scripts/lib

    Нам понадобятся стандартные библиотеки для работы c сокетами и SSL.
    sudo apt-get install lua-socket lua-sec

    Также пригодится библиотека для кодирования и декодирования JSON. Я остановил свой выбор на библиотеке http://regex.info/blog/lua/json. Скачиваем её и размещаем в соответствующей папке.
    
    wget http://regex.info/code/JSON.lua -O lib/json.lua

    И вот теперь всё готово для пришествия нашего кода в этот мир. В папке скриптов создаём файл cidlookup.lua и твёрдой клавиатурой вносим туда следующий код:

    /usr/local/freeswitch/scripts/cidlookup.lua
    -- Параметры соединения с iTop.
    local itop_addr = 'https://<itop_address:port>';
    local itop_user = 'admin';
    local itop_pass = 'password';
     
    -- Загружаем библиотеки.
    local json = (loadfile '/usr/local/freeswitch/scripts/lib/json.lua')();
     
    -- Принимаем из аргументов номер.
    --[[
    	Обратите внимание на две следующие строки. Они указывают на различия в принимаемых аргументах при вызове
    	из командной строки и из Freeswitch. При тестировании из командной строки надо раскомментировать верхнюю
    	строку и закомментировать нижнюю. И наоборот. Да, я знаю, можно было сделать изящнее и универсальнее. Но
    	я не так хорошо знаю Lua, чтобы сделать это хорошо. Может когда-нибудь.
    ]]--
    -- local phone = arg[1];
    local phone = argv[1];
     
    -- Формируем команду.
    local command = {
    	operation = 'core/get',
    	class = 'Person',
    	key = 'SELECT Person AS P WHERE P.phone = "' .. phone .. '" OR P.add_phone = "' .. phone .. '" OR P.add_phone_2 = "' .. phone .. '" OR P.mobile_phone = "' .. phone .. '" OR P.add_mobile_phone = "' .. phone .. '"',
    	output_fields = 'friendlyname,org_id_friendlyname,function'
    };
     
    -- Подключаемся к iTop.
    local http = require 'socket.http';
    local https = require 'ssl.https';
    local ltn12 = require 'ltn12';
     
    local request = 'auth_user=' .. itop_user .. '&auth_pwd=' .. itop_pass .. '&json_data=' .. json:encode(command);
    local respbody = {};
    -- Таймаут требуется, чтобы не вызывать зависание звонка, в случае если iTop по какой-то причине не отвечает.
    -- Не ответил за три секунды - всё, отдаем номер.
    http.TIMEOUT = 3; 
    local body, code, headers, status = https.request {
    	protocol = 'tlsv1',
    	method = 'POST',
            url = 'https://' .. itop_addr .. '/webservices/rest.php?version=1.0',
    	source = ltn12.source.string(request),
            headers = 
                    {
                            ["Accept"] = "*/*",
                            ["Accept-Encoding"] = "gzip, deflate",
                            ["Accept-Language"] = "en-us",
                            ["Content-Type"] = "application/x-www-form-urlencoded",
                            ["content-length"] = string.len(request)
                    },
            sink = ltn12.sink.table(respbody)
        };
     
    -- Если запрос не сработает, нам вернется телефон звонящего.
    caller_id = phone;
    -- Декодируем JSON.
    local response = json:decode(tostring(table.concat(respbody)));
    -- Проверяем, что есть какой-то результат.
    if(not((response == nil) or (response["objects"] == nil))) then
    	local index = next(response["objects"]);
    	local contact = response.objects[index]["fields"];
    -- Формируем выходную строку.
    	caller_id = contact.friendlyname .. "(".. contact.org_id_friendlyname .. (not(contact["function"] == "") and ", " .. contact["function"] or "") .. ")";
    end
     
    --[[
    	Здесь также присутствует отличие при выполнении скрипта из командной строки и из Freeswitch. Для проверки
    	работы скрипта из командной строки комментируем верхнюю строку и раскомментируем нижнюю. И наоборот.
    ]]--
    stream:write(caller_id);
    -- io.write(caller_id .. "\n");
    


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

    lua cidlookup.lua 79101001122
    Василий Пупкевич(Рога и копыта, Суперхомяк)

    Отлично, всё работает как надо. Редактируем скрипт, отключая работу из командной строки. Теперь подключаем скрипт к Freeswitch. Сначала надо убедиться, что у нас есть соответствующий модуль. Заходим в консоль Freeswitch.

    fs_cli

    Проверяем загруженность модуля Lua.

    freeswitch@internal> show modules mod_lua
    type,name,ikey,filename
    api,lua,mod_lua,/usr/local/freeswitch/mod/mod_lua.so
    api,luarun,mod_lua,/usr/local/freeswitch/mod/mod_lua.so
    application,lua,mod_lua,/usr/local/freeswitch/mod/mod_lua.so
    dialplan,LUA,mod_lua,/usr/local/freeswitch/mod/mod_lua.so
    
    4 total.

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

    freeswitch@internal> load mod_lua

    Если Freeswitch не сможет найти модуля для запуска, то надо будет его собрать и доустановить. Будем считать, что эта проблема была вами успешно решена и модуль загружен. Пробуем выполнить наш скрипт:

    freeswitch@internal> lua cidlookup.lua 79101001122
    Василий Пупкевич(Рога и копыта, Суперхомяк)

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

    <!-- Активируем поиск по номеру телефона. -->
    <!-- Присваиваем значение по умолчанию для номера телефона. -->
    <extension name="cid_number_cleanup" continue="true">
    	<condition field="caller_id_number" expression="^(\d+)$">
    		<action application="set" data="effective_caller_id_number=$1" inline="true"/>
    	</condition>
    </extension>
     
    <!-- Присваиваем значение по умолчанию для имени контакта. -->
    <extension name="cid_name_cleanup" continue="true">
    	<condition field="caller_id_name" expression="^(\d+)$">
    		<action application="set" data="effective_caller_id_name=$1" inline="true"/>
    	</condition>
    </extension>
     
    <!--
    	Значения по умолчанию оберегают нас от ситуации, когда поиск номера в телефонной книге невозможен,
    	не успевает выполниться или модуля вообще нет. В этом случае мы просто получим вместо имени контакта
    	его номер.
    -->
     
    <extension name="cid_lookup" continue="true">
    	<condition field="${module_exists(mod_lua)}" expression="true"/>
    	<condition field="caller_id_name" expression="^(\d+)$|^$"/>
    	<condition field="caller_id_number" expression="^(\d+)$">
    		<action application="set" data="effective_caller_id_name=${lua(cidlookup.lua ${caller_id_name})}"/>
    	</condition>
    </extension>

    Выполняем перезагрузку диалплана командой

    fs_cli -x reloadxml

    И наслаждаемся результатом.

    Вынесение


    Да, я знаю, можно улучшать и улучшать. Можно связать с mod_curl и упростить код, можно допилить и оптимизировать скрипт, не спорю с этим. Нет предела совершенству. Но любая дорога начинается с первого шага, и если эта статья кому-то пригодится в его нелегком труде, значит, писалась не зря. =) Засим желаю здравствовать.

    P.S. Надеюсь, кому-нибудь пригодится. Буду рад вашим комментариям.

    Business Infinity Group

    22,83

    IT-инфраструктура для бизнеса

    Поделиться публикацией
    Комментарии 9
      0
      Хорошая статья, мы правда это реализовывали на уровне устройств, телефоны лукапят в LDAP и подставляет номер > имя контакта, и при входящих и при исходящих.

      Спасибо, думаю пригодится интеграция с базой :)

      Поставил бы как минмум + за использование фрисвича :) но карма пока не позволяет
        0
        Ага, тоже хорошая вещь, но у меня против нее было несколько «но». У нас, в основном, используются софтфоны — аппаратный телефон всего один. А они очень разношерстные и поддерживают все разные протоколы для телефонной книги. Дополнительно все осложняется тем, что кто-то сидит на Винде, кто-то на Линухах, где адекватных софтфонов вообще раз-два и обчелся. И вдобавок хотелось, чтобы поименованные записи попадали в CDR, что при локальном запросе соответствия номер -> контакт недостижимо. У меня, на самом деле, есть набросок скрипта, который готовит телефонную книгу для MicroSIP, но он пока не дописан. Предполагалось его размещать тоже на Freeswitch.
        0
        Может просто начать использовать FusionPBX? Заодно помочь в разработке и тестировании этого уникального продукта?
          0
          Вы не поверите — используем. Но это не отменяет необходимости интегрирования. На FusionPBX переехали относительно недавно, до этого была еще пара попыток переехать, обе неудачные. Переезд, кстати, состоялся, в основном, для того, чтобы дать доступ к некоторым сервисам телефонии (просмотр статуса линий, просмотр CDR) другим сотрудникам. Мне и в консоли жилось хорошо. Но все равно пока впечатление, как при плохо подогнанном пиджаке, вроде норм, но тут чутка жмет, тут перекошено. Мной внесены некоторые изменения в скрипты FusionPBX, в частности, добавлены per-user variables для гибкого управления тем, кому с какой исходящей линии звонить. Изменен extension blacklist-а, потому что я хотел, чтобы спамеры слушали мартышек. Freeswitch всегда меня поражал своей гибкостью. Ты думаешь — а вот сейчас я что-нибудь эдакое как проверну! И оно работало. о_О С FusionPBX ограничений стало больше. Но это так, мое старческое брюзжание. =)
            0
            Не, все верно. Тем кто привык работать в консоле и делать все руками, то FusionPBX не айс. Он приятен в первую очередь людям, которые сидели на веб интерфейсах астериска например.
            Для себя выбрал именно консольный фриисвитч. И дальше уже на голый свитч делаю обвязку необходимую.
              0
              Да-да, вы меня прекрасно понимаете. Когда переносил диалплан в FusionPBX, пришлось немного поплакать кровавыми слезами. Потому что любовно написанные диалпланы никак не лезли в условную логику FusionPBX. Какие-то цифры, какие-то необязательные редиректы, необходимость держать в голове то, что extension-ы входящей маршрутизации лежат в определенном месте общего набора extension-ов. Что можно рабочее время запилить прямо в extension, но тогда оно не будет отображаться в web-интерфейсе. Или запилить в интерфейсе и понять, что для него создался отдельный extension и непонятно, как оттуда прыгнуть назад. Документация… не будем о грустном. Но при этом это пока единственный адекватный интерфейс. Остальные или не развиваются, или полуфабрикат, как Kazoo. Который круто выглядит по возможностям, но для нас дикий оверинжинеринг.
          0
          Стоит аппаратная АТС Panasonic, но уже устарела а апгрейды стоят дорого. Вот тоже думаем переползать на софтовое решение. Начали тестировать Elastix, как бы из коробки красиво все запускалось, но там сейчас переход на другой движок, причем проприетарный. А есть что-то подобное на freeswitch?
            0
            Можно посмотреть в сторону FusionPBX. Но надо понимать, что написание диалпланов для него требует понимания того, как они вообще устроены и работают в Freeswitch. В Elastix и FreePBX все-таки попроще. Я бы вам посоветовал остановиться на FreePBX, раз вам Elastix приглянулся.
            0
            + за использование FreeSWITCH в карму точно заслуженный :)

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

            Самое читаемое