Розробка модулів FreePBX

image
FreePBX — це найбільш популярний веб-інтерфейс для налаштування серверів на базі Asterisk. FreePBX — це гнучка, модульна система. Пропонує багатий функціонал з налаштування станцій. Найприємніше — це проект з відкритим вихідним кодом.
На практиці часто виникає необхідність вирішити унікальну задачу, для якої не досить типових можливостей FreePBX.
У рамках статті я опишу можливості розширення функціоналу додатковими модулями.
Опишу процес розробки нового модуля…

Коли потрібна розробка модуля?

Тиражований продукт — у разі, якщо підтримувати доводиться кілька однотипних АТС і одна і та ж фіча необхідна багатьом. Наприклад (зворотний дзвінок, інтеграція з бітрікс чатом)
Зручність налаштування — завантажити модуль простіше і швидше, ніж правити конфіги вручну. Один раз заклали логіку, і кожна наступна інсталяція вимагає менше часу.
Знижуємо шанс на помилку — базові настройки зазвичай виробляємо на тестовому стенді, при перенесенні в продакшн можуть виникнути складнощі з залежностями. Ми можемо помістити всі необхідні файли у наш модуль і встановити їх разом з ним.
ВЕЛИКІ Можливості — розробка модулів дозволяє більш гнучко / тонко налаштувати АТС, приміром можливо перекрити diaplan, або додавати в існуючий свої рядки з точністю до номера пріоритету.

Схема роботи Asterisk — FreePBX — DB


Asterisk може використовувати базу даних для зберігання історії дзвінків.
FreePBX — взаємодіє з базою даних, що зберігає і отримує налаштування. Модулі FreePBX можуть звертатися до бази даних для аналізу історії дзвінків.
Одна з функцій FreePBX — створення конфігураційних файлів і поставка AGI скриптів Asterisk. FreePBX знає все про системних директоріях Asterisk, може керувати Asterisk.

FreePBX — модульна система


Основа FreePBX — модуль "FreePBX Framework" (далі просто Framework). По своїй суті — це модуль керуючий іншими модулями. Framework надає базовий web інтерфейс:
  • Вікно авторизації
  • Головне меню
  • Сторінка «Module Admin»

Кожен модуль може розширити функціонал FreePBX, приміром додати конфіги і розширити web інтерфейс.
Всі модулі істотно залежать від Framework, і можуть зовсім не залежати від інших модулів. Приклади модулів:
  • Соге — надає функціонал «Trunk» / «In. rout» / «Out. rout» і функціонал«Application» — «Extensions».
  • IVR — надає функції голосового меню
  • Queues — функції черг викликів і т. д

Збереження конфігурації FreePBX

Після того, як ми щось змінили у налаштуваннях FreePBX з'являється кнопка "Apply Config". На схемі нижче описаний процес генерації конфігураційних файлів.

Першим в справу вступає модуль Framework

  • Виробляє збереження налаштувань в базу даних
  • Створює базові конфіги, наприклад extensions.conf extensions_additional.conf

Далі Framework звертається до додаткових модулів, наприклад модуль core

  • Використовує функціонал модуля Framework і доповнює файл extensions_additional.conf своїм dialplan
  • Створює файли sip_additional.conf, res_odbc_additional.conf та інші

Ми, як розробники, можемо додати свій модуль

  • Використовувати функції Framework для генерації extensions_additional.conf
  • Використовувати функції інших модулів, наприклад core для правки конфіги цього модуля: sip_additional.conf, res_odbc_additional.conf
  • Створювати свої конфігураційні файли
  • Використовувати свої AGI скрипти
  • Розширювати web інтерфейс своїми сторінками / або своїми web інтерфейсами

Структура модуля

module.xml
У цьому файлі описуються основні властивості модуля.
Найбільш важливі властивості:
  • "rawname" — унікальне ім'я модуля, не повинно містити спецсимволи
  • "name" — представлення модуля, як він буде відображатися в "Module admin, не повинно містити спецсимволи
  • "version" версія модуля
  • "category" — категорія основного меню
  • "menuitems" — представлення модуля в меню, може містити в собі тегиmenuitems" визначають імена сторінок
  • "depends" — основні залежності модуля
Структура файлу детально описана в документації.
Приклад файлу наведено нижче:
<module>
<rawname>pt1ctraining</rawname>
<name>AA Training module</name>
<version>2.11.0.6</version>
<publisher>telefon1c.ua</publisher>
<license>GPLv3+</license>
<licenselink>http://www.gnu.org/licenses/gpl-3.0.txt</licenselink>
<category>Applications</category>
<menuitems>
<pt1ctraining>AA Training module (MIKO LCC)</pt1ctraining>
</menuitems>
<changelog>
*2.11.0.6* Перший реліз
</changelog>
<depends>
<phpversion>5.3.3</phpversion>
<module>pt1c ge 2.11.3.18</module>
</depends>
</module>

install.php
У цьому файлі описуємо інструкції по установці модуля.
У цьому скрипті можливо звернутися до «global» змінним FreePBX.
"$db" дозволяє взаємодіяти з базою даних FreePBX.
Приклад створення таблиці для зберігання налаштувань модуля:
out("Початок установки модуля.");

global $db;
$sql = "CREATE TABLE IF NOT EXISTS pt1ctraining (
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
pt1ctraining_id INTEGER NOT NULL,
description VARCHAR( 150 ),
destination VARCHAR( 50 ),
content_app text NOT NULL,
path_to_php_agi VARCHAR( 50 )
);";
$check = $db- > query($sql);
if (DB::IsError($check)) {
die_freepbx( "Can not create `pt1ctraining` table: " . $check->getMessage() . "\n");
}

Зверніть увагу, що немає необхідності вказувати параметри підключення до бази даних.
"$amp_conf" містить параметри конфігурації FreePBX (зазвичай визначені у/etc/freepbx.conf та /etc/amportal.conf). Приклад використання:
global $amp_conf; 
out("AMPDBENGINET: " + $amp_conf["AMPDBENGINE"]);

Функція out() дозволяє виводити інформацію про хід встановлення модуля у вікно повідомлень:

Приклад додавання налаштування в розділ "Settings — Advanced Settings":

$freepbx_conf =& freepbx_conf::create();
if (!$freepbx_conf->conf_setting_exists('pt1ctraining_test')) {
$set = array();
$set['value'] = 'all';
$set['defaultval'] = &$set['value'];
$set['readonly'] = 0;
$set['hidden'] = 0;
$set['level'] = 3;
$set['module'] = 'pt1ctraining';
$set['category'] = 'AA Test Module';
$set['emptyok'] = 0;
$set['sortorder'] = 11;
$set['name'] = 'Test settings.';
$set['description'] = 'test Description settings.';
$set['type'] = CONF_TYPE_TEXT;
$freepbx_conf->define_conf_setting('pt1ctraining_test',$set,true);
}

Директорії etc та agi-bin
При установці модуля вміст директорій буде скопійовано у відповідні директорії asterisk:

Uninstall.php
Скрипт описує інструкції з видалення модуля. Чистимо за собою.
<?php
if (!defined('FREEPBX_IS_AUTH')) { die('No direct script access allowed'); }
sql('DROP TABLE pt1ctraining');
?>

У прикладі вище описаний приклад використання глобальної функції з ім'ям "sql". В якості аргументу передаємо тест запиту для видалення таблиці.
Крім того, використовується цікавий виклик "defined('FREEPBX_IS_AUTH')", перевірка авторизований користувач. Краще її використовувати для всіх php скриптів.
Всі скрипти і файли з іменем index.php публікуються на web сервері і доступи ззовні.
Якщо користувач спробує звернутися до скрипта без авторизації — отримає повідомлення "No direct script access allowed"

Серце модуля — functions.inc.php

У цьому файлі ми реалізуємо функції нашого модуля, ключові можливості:
  • Створювати свої конфігураційні файли
  • Додавати варіанти «destination»
  • Використовувати функції інших модулів
  • Правити файл extensions_additional.conf та інші
functions.inc.php можуть бути визначені hook-функції, які будуть викликані модулем framework при генерації конфіги.
Такі функції зазвичай іменуються наступним чином:
function ModuleName_FunctionName($engine) {
//
//
}

Приклад реальної функції
Визначимо dialplan у extensions_additional.conf
function pt1ctraining_get_config($engine) {
global $ext; 

switch ($engine) {
case 'asterisk':
// Створюємо свій контекст.
$context = 'ext-pt1ctraining';
$розширеннями = '_X!';
$ext->add($context, $розширеннями, ", new ext_agi('pt1ctraining_AGI.php'));
$ext->add($context, $розширеннями, ", new ext_hangup("));
}
}

Функція "get_config" буде викликана при створенні конфігураційних файлів, коли буде натиснута кнопка "Apply Config".
В якості параметра передано рядок "$engine" — ім'я движка, зазвичай «зірочка».
Для створення dialplan використовувалася глобальна змінна "$ext", містить екземпляр класу "extensions", клас визначений у файлі "/var/www/html/admin/libraries/extensions.class.php і надає нам набір інструментів для генерації dialplan.
Результат роботи буде доданий у extensions_additional.conf:
[ext-pt1ctraining]
розширеннями => _X!,1,AGI(pt1ctraining_AGI.php)
розширеннями => _X!,n,Hangup

Класи "ext_agi" і "ext_hangup" також визначені в "extensions.class.php".
Приклад додавання в секцію "[globals]" файлу extensions_additional.conf
global $ext;
// Додамо ініціалізацію змінної в сеции "global"
$ext->addGlobal('PT1C_TR', 'test');
$ext->addGlobal("#include extension_add_pt1c.conf"."\n;", '\n');

Результат роботи:
[globals]
CFDEVSTATE = TRUE
CAMPONTOGGLE = *84
DNDDEVSTATE = TRUE
FMDEVSTATE = TRUE
PT1C_TR = test
#include extension_add_pt1c.conf
; = \n
QUEDEVSTATE = TRUE

Для підключення додаткового файлу використовував хитрість у вигляді перенесення рядка — іншого рішення поки немає.
Використовуємо налаштування з «Advanced Settings

Отримання глобальної налаштування FreePBX.
$freepbx_conf =& freepbx_conf::create();
$pt1c_events = $freepbx_conf->get_conf_setting('pt1ctraining_test',true);
// Созадем dialplan
$ext->add('ext-pt1ctraining-test', '_X!', ", new ext_noop("$pt1c_events"));
$ext->add('ext-pt1ctraining-test', '_X!', ", new ext_hangup("));

Результат у файлі extensions_additional.conf:
[ext-pt1ctraining-test]
розширеннями => _X!,1,Noop(Privet!!!)
розширеннями => _X!,n,Hangup

Правка res_odbc_additional.conf
Використовуємо функціонал модуля core:
global $core_conf, $amp_conf;

$section = 'PT1C_asteriskcdrdb';
$core_conf->addResOdbc($section, array('enabled' => 'yes'));
$core_conf->addResOdbc($section, array('dsn' => 'MySQL-asteriskcdrdb'));
$core_conf->addResOdbc($section, array('pooling' => 'no'));
$core_conf->addResOdbc($section, array('limit' => '1'));
$core_conf->addResOdbc($section, array('pre-connect' => 'yes'));
$core_conf->addResOdbc($section, array('username' => $amp_conf['AMPDBUSER']));
$core_conf->addResOdbc($section, array('password' => $amp_conf['AMPDBPASS']));

Результат роботи в res_odbc_additional.conf:
[PT1C_asteriskcdrdb]
enabled=>yes
dsn=>MySQL-asteriskcdrdb
pooling=>no
limit=>1
pre-connect=>yes
username=>freepbxuser
password=>d52d251931c2

Створюємо свій конфіг
Може з'явитися потреба створити свої конфігураційні файли.
Для цих цілей ми повинні визначити клас з ім'ям "ModuleName_conf". Приклад класу наведено нижче:
// Клас буде використовуватися для генерації конфігураційних файлів.
class pt1ctraining_conf {
function get_filename() {
$files = array(
'extension_additional_pt1ctraining.conf',
);
return $files;
}
function generateConf($file) {
switch ($file) {
case 'extension_additional_pt1ctraining.conf':
return $this->generate_conf();
break;
}
}
function generate_conf() {
$output = "[test] ; row 1 \n; Privet";
return $output;
}
}

Метод "get_filename" повертає масив файлів, які будуть створені.
Метод "generateConf" приймає як параметр ім'я файлу і повертає текстове вміст цього файлу.
Визначимо свої destination

Кожен, хто працював з FreePBX бачив поле Set Destination. Кожен модуль може додавати свої точки призначення. Для цього необхідно визначити дві процедури:
// Впливає на появу позиції в списку в полі destination.
// 
function pt1ctraining_getdest($розширеннями) {
return array('pt1ctraining,'.$розширеннями.',1');
}
// Після вибору "application" з'явиться поле для вибору збереженого маршруту.
// 
function pt1ctraining_destinations() { 
$extens[] = array('destination' => 'ext-pt1ctraining,${РОЗШИРЕННЯМИ},1' , 'description' => 'IVR');
$extens[] = array('destination' => 'ext-pt1ctraining_2,${РОЗШИРЕННЯМИ},1', 'description' => 'IVR_2');
$extens[] = array('destination' => 'ext-pt1ctraining_3,${РОЗШИРЕННЯМИ},1', 'description' => 'IVR_3');

return $extens;
}

Функція "pt1ctraining_getdest" повинна повернути масив з одним значенням "стоку". Формат “array('ModuleName,'.$розширеннями.',1')"
Функція "pt1ctraining_destinations" повинна повернути масив з точками призначення.
Кожен елемент масиву — асоціативний масив з двома ключами:
'Destination' — містить Goto сумісні параметри, надалі перенаправлення буде здійснюватися в dialplan засобами Goto
'Description' містить назву точки призначення, саме так буде представлено значення користувачеві

Сторінки модуля

В директорії модуля може бути визначено скільки завгодно файлів з ім'ям формату "page.ModuleName.php", приклад "page.pt1ctraining.php".
У цих файлах ми можемо визначити форму html для взаємодії з користувачем.
Щоб web інтерфейс «дізнався про існування сторінки, ми повинні вказати на ідентифікатор сторінки у файлі „module.xml“ в тезі „menuitems“ тег з ім'ям сторінки:
<menuitems>
<pt1ctraining>AA Training module (MIKO LCC)</pt1ctraining>
</menuitems>

Приклад сторінки
<form autocomplete="off" name="edit" action="<?php $_SERVER['PHP_SELF'] ?>" method="post" onsubmit="return edit_onsubmit();">
<input type="hidden" name="itemid" value="<?php echo $itemid?>">
<input type="hidden" name="action" value="<?php echo ($itemid ? 'edit' : 'add') ?>">
<table>
<tr><td colspan="4"><h5>Разрабатваем модуль<hr></h5></td></tr>
<tr>
<td><a href="#" class="info">Найменування<span>Ім'я програми</span></a></td>
<td><input type="text" name="description" class="" value="<?php echo($thisItem['description']); ?>"></td>
</tr>
<tr>
<td><a href="#" class="info">Dialplan:<span>Text dialplan application.</span></a></td>
<td><textarea name="content_app" cols=50 rows=5><?php echo($thisItem['content_app']); ?></textarea></td>
</tr>
</table>
</form>

Збірка модуля

Тут все просто, упаковка модуля повинна бути здійснена засобами tar:
tar -czf pt1ctraining “pt1ctraining-2.11.0.6.tgz";

Якщо модуль підготовляється для FreePBX 12+ то бажано підписати модуль цифровим підписом разработичка, докладно описані в офіційній документації.
Підписати модуль можна використовуючи пакет утиліт devtools:
sign.php pt1ctraining "KEY"

Де, „pt1ctraining“ — каталог з модулем.

Висновок

FreePBX цікава платформа. Пропонує великий функціонал для налаштування АТС.
Для випадку, коли фукнционала FreePBX не достатньо є можливість розширити набір функцій засобами додаткового модуля.
Власний модуль дозволить отримати більш тонке налаштування АТС:
  • Додавання своїх dialplan
  • Доповнення існуючих конфігів, наприклад extensions_additional.conf
  • Додавання нових конфігураційних файлів
  • Правка dialplan, створених іншими модулями
В якості джерел знань рекомендую використовувати:
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.