Историята на един проект или как прекарах 7 години в създаване на телефонна централа, базирана на Asterisk и Php

Със сигурност много от вас, като мен, са имали идея да направят нещо уникално. В тази статия ще опиша техническите проблеми и решения, с които трябваше да се сблъскам при разработването на PBX. Може би това ще помогне на някой да реши собствената си идея и някой да следва добре утъпкания път, защото аз също се възползвах от опита на пионерите.

Историята на един проект или как прекарах 7 години в създаване на телефонна централа, базирана на Asterisk и Php

Идея и основни изисквания

И всичко започна просто с любов към звездичка (рамка за изграждане на комуникационни приложения), автоматизация на телефония и инсталации Безплатна телефонна централа (уеб интерфейс за звездичка). Ако нуждите на компанията бяха без конкретика и попадаха във възможностите Безплатна телефонна централа - всичко е страхотно. Цялата инсталация се извърши в рамките на XNUMX часа, компанията получи конфигурирана телефонна централа, удобен интерфейс и кратко обучение плюс поддръжка при желание.

Но най-интересните задачи бяха нестандартни и тогава не беше толкова приказно. звездичка може да направи много, но за да поддържа уеб интерфейса в работно състояние, беше необходимо да отделите многократно повече време. Така че един малък детайл може да отнеме много повече време от инсталирането на останалата част от PBX. И въпросът не е, че написването на уеб интерфейс отнема много време, а по-скоро въпросът е в архитектурните характеристики Безплатна телефонна централа. Архитектурни подходи и методи Безплатна телефонна централа беше изложено по времето на php4 и в този момент вече имаше php5.6, на който всичко можеше да бъде направено по-просто и по-удобно.

Последната капка бяха графичните диалпланове под формата на диаграма. Когато се опитах да създам нещо подобно за Безплатна телефонна централа, разбрах, че ще трябва значително да го пренапиша и ще бъде по-лесно да създам нещо ново.

Основните изисквания бяха:

  • проста настройка, интуитивно достъпна дори за начинаещ администратор. По този начин компаниите не изискват поддръжка на PBX от наша страна,
  • лесна модификация, така че задачите да се решават в подходящо време,
  • лесна интеграция с PBX. U Безплатна телефонна централа нямаше API за промяна на настройките, т.е. Не можете например да създавате групи или гласови менюта от приложение на трета страна, а само от самия API звездичка,
  • opensource - за програмистите това е изключително важно за модификации за клиента.

Идеята за по-бързо развитие беше цялата функционалност да се състои от модули под формата на обекти. Всички обекти трябваше да имат общ родителски клас, което означава, че имената на всички основни функции вече са известни и следователно вече има реализации по подразбиране. Обектите ще ви позволят драстично да намалите броя на аргументите под формата на асоциативни масиви с низови ключове, които можете да намерите в Безплатна телефонна централа Това беше възможно чрез изследване на цялата функция и вложените функции. В случай на обекти, баналното автоматично довършване ще покаже всички свойства и като цяло ще опрости живота многократно. Плюс това, наследяването и предефинирането вече решават много проблеми с модификациите.

Следващото нещо, което забавяше времето за преработка и си струваше да се избягва, беше дублирането. Ако има модул, който отговаря за набирането на служител, тогава всички други модули, които трябва да изпратят обаждане до служител, трябва да го използват, а не да създават свои собствени копия. Така че, ако трябва да промените нещо, тогава ще трябва да промените само на едно място и търсенето на „как работи“ трябва да се извърши на едно място, а не да се търси в целия проект.

Първа версия и първи грешки

Първият прототип е готов за една година. Цялата PBX, както беше планирано, беше модулна и модулите можеха не само да добавят нова функционалност за обработка на повиквания, но и да променят самия уеб интерфейс.

Историята на един проект или как прекарах 7 години в създаване на телефонна централа, базирана на Asterisk и Php
Да, идеята за изграждане на dialplan под формата на такава схема не е моя, но е много удобна и направих същото за звездичка.

Историята на един проект или как прекарах 7 години в създаване на телефонна централа, базирана на Asterisk и Php

Като напишат модул, програмистите вече могат:

  • създайте своя собствена функционалност за обработка на разговори, която може да бъде поставена на диаграмата, както и в менюто с елементи вляво,
  • създайте свои собствени страници за уеб интерфейса и добавете вашите шаблони към съществуващи страници (ако разработчикът на страницата е предвидил това),
  • добавете вашите настройки към основния раздел с настройки или създайте свой собствен раздел с настройки,
  • програмистът може да наследи от съществуващ модул, да промени част от функционалността и да я регистрира под ново име или да замени оригиналния модул.

Ето как например можете да създадете свое собствено гласово меню:

......
class CPBX_MYIVR extends CPBX_IVR
{
 function __construct()
 {
 parent::__construct();
 $this->_module = "myivr";
 }
}
.....
$myIvrModule = new CPBX_MYIVR();
CPBXEngine::getInstance()->registerModule($myIvrModule,__DIR__); //Зарегистрировать новый модуль
CPBXEngine::getInstance()->registerModuleExtension($myIvrModule,'ivr',__DIR__); //Подменить существующий модуль

Първите сложни реализации донесоха първата гордост и първите разочарования. Радвах се, че работи, че вече успях да възпроизведа основните характеристики Безплатна телефонна централа. Радвах се, че хората харесаха идеята за схемата. Все още имаше много възможности за опростяване на разработката, но дори по това време някои от задачите вече бяха улеснени.

API за промяна на конфигурацията на PBX беше разочарование - резултатът изобщо не беше това, което искахме. Възприех същия принцип като в Безплатна телефонна централа, като щракнете върху бутона Приложи, цялата конфигурация се пресъздава и модулите се рестартират.

Изглежда така:

Историята на един проект или как прекарах 7 години в създаване на телефонна централа, базирана на Asterisk и Php
*Dialplan е правило (алгоритъм), по което се обработва повикване.

Но с тази опция е невъзможно да се напише нормален API за промяна на настройките на PBX. Първо, операцията по прилагане на промените към звездичка твърде дълъг и ресурсоемък.
Второ, не можете да извикате две функции едновременно, защото и двете ще създадат конфигурацията.
Трето, той прилага всички настройки, включително тези, направени от администратора.

В тази версия, както в Аскозия, беше възможно да се генерира конфигурация само на променени модули и да се рестартират само необходимите модули, но всичко това са половин мерки. Наложи се промяна на подхода.

Втора версия. Нос извади опашка остана

Идеята за решаване на проблема не беше да се пресъздаде конфигурацията и диалпланът за звездичка, но запазва информация в базата данни и чете от базата данни директно, докато обработва повикването. звездичка Вече знаех как да чета конфигурации от базата данни, просто променете стойността в базата данни и следващото извикване ще бъде обработено, като се вземат предвид промените, а функцията беше идеална за четене на параметри на диалплан REALTIME_HASH.

В крайна сметка нямаше нужда дори от рестартиране звездичка при промяна на настройките и всички настройки започнаха да се прилагат незабавно към звездичка.

Историята на един проект или как прекарах 7 години в създаване на телефонна централа, базирана на Asterisk и Php

Единствените промени в плана за набиране са добавянето на вътрешни номера и намеци. Но това бяха малки точкови промени

exten=>101,1,GoSub(‘sub-callusers’,s,1(1)); - точечное изменение, добавляется/изменяется через ami

; sub-callusers – универсальная функция генерится при установке модуля.
[sub-callusers]
exten =>s,1,Noop()
exten =>s,n,Set(LOCAL(TOUSERID)=${ARG1})
exten =>s,n,ClearHash(TOUSERPARAM)
exten =>s,n,Set(HASH(TOUSERPARAM)=${REALTIME_HASH(rl_users,id,${LOCAL(TOUSERID)})})
exten =>s,n,GotoIf($["${HASH(TOUSERPARAM,id)}"=""]?return)
...

Можете лесно да добавите или промените линия в плана за набиране, като използвате Ami (интерфейс за управление звездичка) и не се изисква рестартиране на целия диалплан.

Това реши проблема с конфигурационния API. Можете дори директно да влезете в базата данни и да добавите нова група или да промените, например, времето за набиране в полето „време за набиране“ за групата и следващото обаждане вече ще продължи определеното време (Това не е препоръка за действие, тъй като някои API операции изискват Ami обаждания).

Първите трудни изпълнения отново донесоха първата гордост и разочарование. Радвах се, че проработи. Базата данни стана критична връзка, зависимостта от диска се увеличи, имаше повече рискове, но всичко работеше стабилно и без проблеми. И най-важното, сега всичко, което може да се направи чрез уеб интерфейса, може да се направи чрез API и се използват същите методи. Освен това уеб интерфейсът се отърва от бутона „прилагане на настройките към PBX“, за който администраторите често забравят.

Разочарованието беше, че развитието стана по-сложно. От първата версия езикът PHP генерира диалплан на езика звездичка и изглежда напълно нечетливо, плюс самия език звездичка за писане на диалплан е изключително примитивно.

Как изглеждаше:

$usersInitSection = $dialplan->createExtSection('usersinit-sub','s');
$usersInitSection
 ->add('',new Dialplanext_gotoif('$["${G_USERINIT}"="1"]','exit'))
 ->add('',new Dialplanext_set('G_USERINIT','1'))
 ->add('',new Dialplanext_gosub('1','s','sub-AddOnAnswerSub','usersconnected-sub'))
 ->add('',new Dialplanext_gosub('1','s','sub-AddOnPredoDialSub','usersinitondial-sub'))
 ->add('',new Dialplanext_set('LOCAL(TECH)','${CUT(CHANNEL(name),/,1)}'))
 ->add('',new Dialplanext_gotoif('$["${LOCAL(TECH)}"="SIP"]','sipdev'))
 ->add('',new Dialplanext_gotoif('$["${LOCAL(TECH)}"="PJSIP"]','pjsipdev'))

Във втората версия диалпланът става универсален, включва всички възможни опции за обработка в зависимост от параметрите и размерът му се увеличава значително. Всичко това значително забави времето за разработка и самата мисъл, че отново е необходимо да се намесвам в диалплана, ме натъжи.

Трета версия

Идеята за решаване на проблема не беше генериране звездичка dialplan от php и използвайте FastAGI и напишете всички правила за обработка в самия PHP. FastAGI Тя позволява на звездичка, за да обработите повикването, свържете се към гнездото. Получавайте команди от там и изпращайте резултати. Така логиката на диалплана вече е извън границите звездичка и може да бъде написан на всеки език, в моя случай на PHP.

Имаше много опити и грешки. Основният проблем беше, че вече имах много класове/файлове. Отне около 1,5 секунди, за да създадете обекти, да ги инициализирате и да се регистрирате един с друг и това забавяне на повикване не е нещо, което може да бъде игнорирано.

Инициализацията трябваше да се случи само веднъж и следователно търсенето на решение започна с писане на услуга в php с помощта Pthreads. След седмица на експериментиране тази опция беше отложена поради сложността на това как работи това разширение. След месец тестване също трябваше да изоставя асинхронното програмиране в PHP; имах нужда от нещо просто, познато на всеки начинаещ PHP, а много разширения за PHP са синхронни.

Решението беше нашата собствена многонишкова услуга в C, която беше компилирана с PHPLIB. Той зарежда всички ATS php файлове, изчаква всички модули да се инициализират, добавя обратно извикване един към друг и когато всичко е готово, го кешира. При запитване от FastAGI създава се поток, копие от кеша на всички класове и данни се възпроизвежда в него и заявката се предава на php функцията.

С това решение времето от изпращане на обаждане до нашата услуга до първата команда звездичка намаля от 1,5s на 0,05s и това време зависи леко от размера на проекта.

Историята на един проект или как прекарах 7 години в създаване на телефонна централа, базирана на Asterisk и Php

В резултат на това времето за разработка на диалплан беше намалено значително и мога да оценя това, тъй като трябваше да пренапиша целия диалплан на всички модули в PHP. Първо, методите вече трябва да бъдат написани в php за получаване на обект от базата данни; те бяха необходими за показване в уеб интерфейса, и второ, и това е основното, най-накрая е възможно удобно да се работи с низове с числа и масиви с база данни плюс много PHP разширения.

За да обработите плана за набиране в класа на модула, трябва да внедрите функцията dialplanDynamicCall и аргумент pbxCallRequest ще съдържа обект за взаимодействие звездичка.

Историята на един проект или как прекарах 7 години в създаване на телефонна централа, базирана на Asterisk и Php

Освен това стана възможно отстраняването на грешки в диалплана (php има xdebug и работи за нашата услуга), можете да се движите стъпка по стъпка, като преглеждате стойностите на променливите.

Данни за обаждане

Всякакви анализи и отчети изискват правилно събрани данни и този PBX блок също премина през много проби и грешки от първата до третата версия. Често данните за повикване са знак. Едно обаждане = един запис: кой се е обадил, кой е отговорил, колко време са говорили. В по-интересните опции има допълнителен знак, който показва кой служител на PBX е бил извикан по време на разговора. Но всичко това покрива само част от нуждите.

Първоначалните изисквания бяха:

  • запишете не само кой е телефонната централа, но и кой е отговорил, т.к има прихващания и това ще трябва да се вземе предвид при анализа на повикванията,
  • време преди да се свържете със служител. в Безплатна телефонна централа и някои други телефонни централи, повикването се счита за отговорено веднага щом телефонната централа вдигне телефона. Но за гласовото меню вече трябва да вдигнете телефона, така че всички повиквания се отговарят и времето за изчакване за отговор става 0-1 секунда. Затова беше решено да се спести не само времето преди отговор, но и времето преди свързване с ключови модули (самият модул задава този флаг. В момента той е „Служител“, „Външна линия“),
  • за по-сложен план за набиране, когато повикване пътува между различни групи, беше необходимо да може да се изследва всеки елемент поотделно.

Най-добрият вариант се оказа, когато PBX модулите изпращат информация за себе си при разговори и в крайна сметка записват информацията под формата на дърво.

Изглежда така:

Първо, обща информация за разговора (като всички останали - нищо особено).

Историята на един проект или как прекарах 7 години в създаване на телефонна централа, базирана на Asterisk и Php

  1. Получих обаждане по външна линия "За тестото"в 05:55:52 от номер 89295671458 на номер 89999999999, накрая отговори служител"Секретар 2» с номер 104. Клиентът изчака 60 секунди и говори 36 секунди.
  2. служител "Секретар 2"обажда се на 112 и отговаря служител"Мениджър1» след 8 секунди. Говорят 14 секунди.
  3. Клиентът се прехвърля на Служител "мениджър1“ където продължават да говорят още 13 секунди

Но това е върхът на айсберга; за всеки запис можете да получите подробна хронология на обажданията чрез PBX.

Историята на един проект или как прекарах 7 години в създаване на телефонна централа, базирана на Asterisk и Php

Цялата информация е представена като вложени обаждания:

  1. Получих обаждане по външна линия "За тестото» в 05:55:52 от номер 89295671458 на номер 89999999999.
  2. В 05:55:53 външната линия изпраща повикване към входящата верига "тест»
  3. При обработка на повикване по схемата модулът „обаждане на мениджър“, в който разговорът е 16 секунди. Това е модул, разработен за клиента.
  4. модул "обаждане на мениджър" изпраща обаждане до служителя, отговорен за номера (клиент) "Мениджър1” и изчаква 5 секунди за отговор. Управителят не отговори.
  5. модул "обаждане на мениджър"изпраща обаждане до групата"Мениджъри на CORP" Това са други мениджъри от същата посока (седят в същата стая) и чакат 11 секунди за отговор.
  6. Група "Мениджъри на CORP"обажда се на служители"Мениджър1, Мениджър2, Мениджър3"едновременно за 11 секунди. Без отговор.
  7. Обаждането на мениджъра приключва. И веригата изпраща повикване към модула "Избор на маршрут от 1в" Също така модул, написан за клиента. Тук обаждането беше обработено за 0 секунди.
  8. Веригата изпраща повикване към гласовото меню "Основен с допълнително набиране" Клиентът изчака там 31 секунди, нямаше допълнително набиране.
  9. Схемата изпраща обаждане до групата "Секретарки“, където клиентът изчака 12 секунди.
  10. В група се извикват 2 служители едновременно "Секретар 1"И"Секретар 2" и след 12 секунди служителят отговаря "Секретар 2" Отговорът на повикването се дублира в родителските повиквания. Оказва се, че в групата той е отговорил „Секретар 2", при повикване веригата отговори "Секретар 2" и отговори на повикването по външната линия с "Секретар 2".

Това е запазването на информация за всяка операция и тяхното влагане, което ще позволи просто да се правят отчети. Докладът за гласовото меню ще ви помогне да разберете колко помага или пречи. Изградете отчет за обажданията, пропуснати от служители, като вземете предвид, че повикването е било прихванато и следователно не се счита за пропуснато, и като вземете предвид, че е било групово повикване и някой друг е отговорил по-рано, което означава, че повикването също не е пропуснато.

Такова съхранение на информация ще ви позволи да вземете всяка група поотделно и да определите колко ефективно работи, както и да изградите графика на отговорените и пропуснатите групи по часове. Можете също така да проверите колко точна е връзката с отговорния мениджър, като анализирате трансферите след свързване с мениджъра.

Можете също така да провеждате доста нетипични проучвания, например колко често номера, които не са в базата данни, набират правилното разширение или какъв процент от изходящите повиквания се пренасочват към мобилен телефон.

Какъв е резултатът?

За поддръжката на телефонната централа не се изисква специалист, може и най-обикновен администратор - проверено в практиката.

За модификации не са необходими специалисти със сериозна квалификация, достатъчни са познания по PHP, т.к Вече са написани модули и за SIP протокола, и за опашката, и за повикване на служител и други. Има обвиващ клас за звездичка. За да разработи модул, програмистът може (и в добър смисъл трябва) да извика готови модули. И знанието звездичка са напълно ненужни, ако клиентът поиска да добави страница с някакъв нов отчет. Но практиката показва, че въпреки че програмистите на трети страни могат да се справят, те се чувстват несигурни без документация и нормално отразяване на коментарите, така че все още има място за подобрение.

Модулите могат:

  • създаване на нови възможности за обработка на повиквания,
  • добавяне на нови блокове към уеб интерфейса,
  • наследява от който и да е от съществуващите модули, предефинира функции и ги заменя или просто е леко модифицирано копие,
  • добавете вашите настройки към шаблона за настройки на други модули и много повече.

PBX настройки чрез API. Както е описано по-горе, всички настройки се съхраняват в базата данни и се четат по време на повикването, така че можете да промените всички настройки на PBX чрез API. При извикване на API конфигурацията не се пресъздава и модулите не се рестартират, следователно няма значение колко настройки и служители имате. API заявките се изпълняват бързо и не се блокират една друга.

PBX съхранява всички ключови операции с повиквания с времетраене (изчакване/разговор), влагане и в термините на PBX (служител, група, външна линия, не канал, номер). Това ви позволява да създавате различни отчети за конкретни клиенти и по-голямата част от работата е да създадете удобен за потребителя интерфейс.

Времето ще покаже какво ще последва. Все още има много нюанси, които трябва да бъдат преработени, все още има много планове, но измина една година от създаването на 3-та версия и вече можем да кажем, че идеята работи. Основният недостатък на версия 3 са хардуерните ресурси, но това обикновено е това, за което трябва да платите за улесняване на разработката.

Източник: www.habr.com

Добавяне на нов коментар