Historia e një projekti ose si krijova një qendër ATS mbi Asterisk dhe Php për 7 vjet

Me siguro shumë prej jush, ashtu si unë, kanë pasur idenë për të bërë diçka unike. Në këtë artikull do të përshkruaj problemet dhe zgjidhjet teknike me të cilat u përballa gjatë zhvillimit të një ATS. Ndoshta kjo do të ndihmojë dikë të marrë vendimin për idenë e tij, ose të ndjekë një rrugë të palodhur, sepse edhe unë kam përfituar nga eksperienca e pioneerëve.

Historia e një projekti ose si krijova një qendër ATS mbi Asterisk dhe Php për 7 vjet

Ideja dhe kërkesat kryesore

gjithçka filloi thjesht me dashurinë për Asterisk (kornizë për ndërtimin e aplikacioneve të komunikimit), automatizimin e telefonisë dhe instalimet e FreePBX (interfejsi web për Asterisk). Nëse nevojat e kompanisë nuk ishin të veçanta dhe përputheshin me mundësitë e FreePBX – gjithçka ishte në rregull. E gjithë instalimi zgjati vetëm një ditë, kompania merrte një ATS të konfiguruar, një ndërfaqe miqësore dhe trajnim të shkurtër plus mbështetje sipas dëshires.

Por detyrat më interesante ishin atyre jashtë standartit dhe atëherë gjithçka nuk ishte aq magjike. Asterisk mund të bëjë shumë, por për të ruajtur ndërfaqen web në funksion, duhej të harxhoja shumë më tepër kohë. Pra, një detaj i vogël mund të merrte shumë më tepër kohë se sa instalimi i tërë ATS-së. Çështja nuk ishte se shkrimi i ndërfaqes web zgjaste shumë, por më shumë për arsye të veçorive të arkitekturës FreePBX. Qasjet dhe metodat e arkitekturës FreePBX isha vendosur në kohën e php4, ndërsa atëherë kishte php5.6 që mund të bënte gjithçka më thjeshtë dhe më rehat.

Pika e fundit që më irritonte ishin diagramet grafike të planit të thirrjeve. Kur përpiqesha të krijoja diçka të tillë për FreePBX, kuptova se do të duhej ta riparoja ndjeshëm dhe më mirë ishte të ndihesha me ndonjë gjë të re.

Kërkesat kryesore ishin:

  • konfigurim i thjeshtë, i aksesueshëm intuitivisht për administratören fillestare. Kështu që kompanitë nuk kishin nevojë për mbështetje ATS nga ana jonë,
  • modifikim i lehtë, që detyrat të zgjidheshin brenda një kohe të arsyeshme,
  • përshtatshmëria e integrimit me ATS-në. Në FreePBX nuk kishte API për ndryshimin e parametrave, dmth, nuk ishte e mundur, për shembull, të krijosh grupe ose menutë me zë nga një aplikacion i jashtëm, vetëm API e vetë Asterisk,
  • open-source – për programuesit ky është jashtëzakonisht i rëndësishëm për modifikimet sipas kërkesave të klientit.

Ideja e zhvillimit më të shpejtë ishte që gjithë funksionaliteti të përbëhej nga module në formë objektesh. Të gjithë objektet duhej të kishin një klasë prindore të përbashkët, kështu që emrat e të gjitha funksioneve kryesore ishin tashmë të njohur dhe do të thoshte që tashmë kishte implementime të paracaktuara. Objektet do të lejonin të reduktonin ndjeshëm numrin e argumenteve në forma të asosiativëve me çelësa string, të cilat mund të zhvilloheshin nga hetimi i funksionit dhe funksioneve të brendshme. Në rastin e objekteve, mbushja automatike do të tregonte të gjitha pronësitë dhe gjithashtu do të thjeshtonte shumë gjëra. Plus trashëgimia dhe mbivendosja do të mbyllnin shumë probleme me modifikimet. FreePBX E ardhshme, që ngadalësonte procesin e modifikimit dhe që duhej shmangur – ishin dublikimet. Nëse ka një modul që është përgjegjës për thirrjen tek stafi, të gjitha module e tjera që duhen të dërgojnë thirrjen tek stafi duhet të përdorin pikërisht atë, dhe jo të krijojnë kopje të tyre personale. Kështu, nëse është e nevojshme të ndryshohet diçka, do të duhej të ishte e nevojshme të ndryshohej vetëm në një vend dhe të kërkohet 'si funksionon' në një vend, dhe jo të bëhet kërkim në të gjithë projektin.

Versioni i parë dhe gabimet e para

Prototipi i parë ishte gati vetëm pas një viti. E gjithë ATS, siç ishte planifikuar, ishte modulare, dhe modulet jo vetëm që mund të shtonin funksionalitete të reja për përpunimin e thirrjeve, por gjithashtu të ndryshonin vetë ndërfaqen web.

Po, ideja e ndërtimit të planit të thirrjeve në formën e një diagrami nuk ishte e imja, por ishte mjaft e rehatshme dhe unë bëra të njëjtën gjë për

Historia e një projekti ose si krijova një qendër ATS mbi Asterisk dhe Php për 7 vjet
Me ndihmën e krijimit të modulit, programuesit gjithashtu mund të: Asterisk.

Historia e një projekti ose si krijova një qendër ATS mbi Asterisk dhe Php për 7 vjet

krijonin funksionalitete të veta për përpunimin e thirrjes, që mund të vendoseshin në diagram, si dhe në menunë e elementeve në anën e majtë,

  • krijonin faqe të veta për ndërfaqen web dhe të shtonin template të tyre në faqet ekzistuese (nëse zhvilluesi i faqes e kishte parashikuar këtë),
  • shtonin konfigurime të tyre në skedarin e parametrave kryesore ose të krijonin një skedar të ri me parametrat e tyre,
  • programuesi mund të trashëgojë nga një modul ekzistues, të ndryshojë një pjesë të funksionalitetit dhe regjistrohet me një emër të ri ose të zëvendësojë modul origjinal.
  • Për shembull, kështu mund të krijoni menunë tuaj me zë:

...... class CPBX_MYIVR extends CPBX_IVR { function __construct() { parent::__construct(); $this->_module = "myivr"; } } ..... $myIvrModule = new CPBX_MYIVR(); CPBXEngine::getInstance()->registerModule($myIvrModule,__DIR__); //Regjistro modul të ri CPBXEngine::getInstance()->registerModuleExtension($myIvrModule,'ivr',__DIR__); //Zëvendëso modul ekzistues

Implementimet e para të ndërlikuara sjellin krenarinë e parë dhe zhgënjimin e parë. Mëlinte shumë që funksiononte, që unë tashmë isha në gjendje të riprodhoja funksionalitetet kryesore

Zbatë e parë të komplikuara sollën krenarinë e parë dhe zhgënjimin e parë. Më kënaqte fakti se ajo funksiononte, se tashmë kisha arritur të riprodhoja funksionalitetet kryesore. FreePBX. I was pleased that people liked the idea of the scheme. There were still many options to simplify development, but even at that time, some tasks were already being done more easily.

The disappointment was the API for changing the PBX configuration — it turned out to be completely different from what I wanted. I took the same approach as in FreePBX, where pressing the Apply button recreates the entire configuration and restarts the modules.

Duket kështu:

Historia e një projekti ose si krijova një qendër ATS mbi Asterisk dhe Php për 7 vjet
*Dial plan — the rule (algorithm) by which a call is processed.

But with this option, it is impossible to write a normal API for changing PBX settings. First, the operation of applying changes is Asterisk too long and resource-intensive.
Secondly, you cannot invoke two functions simultaneously, as both would create a configuration.
Third, it applies all settings, including those made by the administrator.

In this version, as in Askozia, it was only possible to generate the configuration for the modified modules and restart only the necessary modules, but all of this was half-measures. A new approach was needed.

Second version. Nose pulled out the tail

The idea for solving the problem was not to recreate the configuration and dial plan for Asterisk, but to save information to the database and read from the database right during the call processing. Asterisk was already able to read configurations from the database, just change the value in the database and the next call would be processed considering the changes, and for reading the parameters of the dial plan, the function REALTIME_HASH.

was perfectly suitable. Asterisk As a result, there was no need to even restart Asterisk.

Historia e një projekti ose si krijova një qendër ATS mbi Asterisk dhe Php për 7 vjet

when changing settings, and all settings began to be applied immediately to The only changes to the dial plan were the additions of internal numbers andhints.

exten=>101,1,GoSub(‘sub-callusers’,s,1(1)); - a point change, added/modified via ami

; sub-callusers – a universal function generated upon module installation.
[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)
...

Adding or changing a line in the dial plan can easily be done via Ami (management interface), and there is no need to reload the entire dial plan. AsteriskThus, the issue with the API for configuration was resolved. You could even go directly into the database and add a new group or change, for example, the dial time in the “dialtime” field of the group and the next call would already last the specified time (This is not a recommendation for action, as some API operations require

calls). Ami The first complex implementations again brought the first pride and disappointment. It was gratifying that it works. The database became a critically important link, dependence on the disk grew, risks increased, but everything worked stably and without problems. And most importantly, now everything that could be done through the web interface could also be done through the API, and the same methods were used. Additionally, the web interface got rid of the button “apply settings to the PBX,” which administrators often forgot.

The disappointment was the complication of development. Even with the first version, the PHP language generates the dial plan in a language

and it looks completely unreadable, plus the language itself Asterisk for writing the dial plan is extremely primitive. Asterisk How it looked:

$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'))

In the second version, the dial plan became universal; it included all possible processing options depending on parameters, and its size significantly increased. All of this greatly slowed down development time, and the very thought that once again I needed to intervene in the dial plan brought sadness.

Third version

The idea for solving the problem was not to generate

the dial plan from PHP, but to use Asterisk FastAGI and write all processing rules directly in PHP. , for processing a call, to connect to the socket. Get commands from there and send results. Thus, the logic of the dial plan is now outside and write all processing rules directly in PHP. lejon Asteriskand can be written in any language, in my case in PHP. Asterisk There were many trials and errors. The main problem was that I already had a lot of classes/files. Creating objects, initializing them, and mutual registration took about 1.5 seconds, and that delay for each call cannot be ignored.

Initialization had to happen only once, and so the search for a solution began with writing a service in PHP using

Pthreads Pthreads. Pas një javë eksperimentesh, ky variant u hoq nga konsiderata për shkak të nuancave të funksionimit të këtij shtesës. Pas një muaji testimesh, gjithashtu u detyruam të braktisnim programimin asinkron në php, na duhej diçka e thjeshtë, e njohur për çdo fillestar në php, dhe shumë shtesa për php ishin sinkronike.

Zgjidhja u bë një shërbim i shumëfishtë në 'C', i cili u kompiluara me PHPLIB. Ai ngarkon të gjitha skedarët php të PBX-it, pret derisa të gjitha modulet të inicializohen, të shtojnë njëri-tjetrin si kolbekë dhe kur gjithçka është gati – e ruan në cache. Kur bëhet një kërkesë në and write all processing rules directly in PHP. krijohet një thread, në të cilin reprodukohet një kopje nga cache e të gjitha klasave dhe të dhënave dhe kërkesa i kalon funksionit php.

Me këtë zgjidhje, koha nga dërgimi i telefonatës në shërbimin tonë deri në komandën e parë Asterisk u shkurtua nga 1,5s në 0,05s dhe ky kohë pak varet nga madhësia e projektit.

Historia e një projekti ose si krijova një qendër ATS mbi Asterisk dhe Php për 7 vjet

Si rezultat, koha për zhvillimin e planit të telefonatës u reduktua ndjeshëm, dhe mund ta vlerësoj këtë pasi më duhej të rishkruaja të gjithë planin e telefonatës të të gjitha moduleve në php. Së pari, në php tashmë duhet të ishin shkruar metoda për marrjen e objekteve nga baza e të dhënave, ato ishin të nevojshme për t'u paraqitur në ndërfaqen web, dhe së dyti, dhe kjo është kryesore – përfundimisht u krijua mundësia për të punuar lehtësisht me stringje të numrave me array-t dhe bazën e të dhënave, përveç shumë shtesave php.

Për trajtimin e planit të telefonatës në klasën e modulit, duhet të implementohet funksioni dialplanDynamicCall dhe argumenti pbxCallRequest do të përmbajë një objekt për ndërveprimin me Asterisk.

Historia e një projekti ose si krijova një qendër ATS mbi Asterisk dhe Php për 7 vjet

Në përmirësim, erdhi mundësia për të debuguar planin e telefonatës (në php ka xdebug dhe për shërbimin tonë funksionon), mund të lëvizni hap pas hapi duke parë vlerat e variableve.

Të dhënat për telefonatat

Për çdo analizë dhe raporte nevojiten të dhëna të mbledhura saktësisht dhe ky bllok PBX gjithashtu kaloi shumë prova dhe gabime nga versioni i parë deri në të tretin. Shpesh të dhënat për telefonatat janë një tabelë. Një telefonatë = një rekord: kush telefonoi, kush u përgjigj, sa folën. Në variantet më interesante ka gjithashtu një tabelë shtesë, kush nga punonjësit e PBX e thërriste gjatë telefonatës. Por gjithçka kjo mbulon vetëm një pjesë të nevojave.

Kërkesat fillestare ishin:

  • të ruhet jo vetëm kush telefonoi PBX, por gjithashtu kush u përgjigj, sepse ka ndërhyrje dhe gjatë analizës së telefonatave do të duhet ta shqyrtojmë këtë,
  • koha deri te lidhja me punonjësin. Në FreePBX dhe disa PBX të tjera, një telefonatë konsiderohet e përgjigjur, sa herë që PBX e merr telefonin. Por për menunë e zërit, duhen ngritur duar, kështu që të gjitha telefonatat bëhen të përgjigjura dhe koha e pritjes për përgjigje bëhet 0-1 sekondë. Prandaj u vendos të ruhej jo vetëm koha deri në përgjigje, por koha deri te lidhja me modulat kryesore (moduli vetë vendos këtë flag. Tani është 'Punonjësi', 'Vija e jashtme'),
  • për një plan më të komplikuar të telefonatës, kur telefonata shkon midis grupeve të ndryshme, kishte nevojë për mundësinë që çdo element të shqyrtohej veçmas.

Më e mira ishte zgjidhja ku modulet e PBX vetë dërgojnë informacionin për telefonatat dhe ndonjëherë ruajnë informacionin në formën e një druri.

Ose si vijon:

Për fillim, informacioni i përgjithshëm mbi telefonatën (siç është tek të gjithë – asgjë e veçantë).

Historia e një projekti ose si krijova një qendër ATS mbi Asterisk dhe Php për 7 vjet

  1. Arriti një telefonatë në vijën e jashtme 'Për test' në 05:55:52 nga numri 89295671458 në numrin 89999999999, në fund e përgjigj punonjësi 'Sekretari2' me numër 104. Klienti priti 60 sekonda dhe foli 36 sekonda.
  2. Punonjësi 'Sekretari2' bën një telefonatë në numrin 112 dhe iu përgjigj punonjësi 'Menaxheri1' pas 8 sekondash. Folën 14 sekonda.
  3. Klienti transferohet te Punonjësi 'menaxher1' ku ata vazhdojnë të flasin edhe 13 sekonda.

Por kjo është maja e ajsbergut, për secilën njohuri mund të marrësh kalimin e detajuar të telefonatës përmes PBX.

Historia e një projekti ose si krijova një qendër ATS mbi Asterisk dhe Php për 7 vjet

Të gjitha informacionet paraqiten në formën e thirrjeve të ngjashme:

  1. Arriti një telefonatë në vijën e jashtme 'Për test» në 05:55:52 nga numri 89295671458 në numrin 89999999999.
  2. Në 05:55:53, linja e jashtme dërgon telefonatën në skemën hyrëse 'test»
  3. Gjatë përpunimit të telefonatës në skemë, thirret moduli 'thirrja e menaxherit', në të cilin telefonata qëndron 16 sekonda. Ky është një modul i zhvilluar për klientin.
  4. Moduli 'thirrja e menaxherit' dërgon telefonatën te punonjësi përgjegjës për numrin (klientin) 'Menaxheri1' dhe pret përgjigjen 5 sekonda. Menaxheri nuk u përgjigj.
  5. Moduli 'thirrja e menaxherit' dërgon telefonatën te grupi 'Menaxherët KORP'. Këta janë menaxherë të tjerë në të njëjtën fushë (ulen në të njëjtën dhomë) dhe pret përgjigjen 11 sekonda.
  6. Grupi 'Menaxherët KORP' thërret punonjësit 'Menaxheri1, Menaxheri2, Menaxheri3' njëkohësisht për 11 sekonda. S'ka përgjigje.
  7. Thirrja e menaxherit përfundon. Dhe skema e telefonatës dërgon në modulin 'Zgjedhja e rrugës nga 1c'. Po ashtu i zhvilluar për klientin. Këtu telefonata u përpunua 0 sekonda.
  8. Skema dërgon telefonatën në menunë e zërit 'Të dhëna me zgjedhje të mëtejshme.». Klienti priti 31 sekond, nuk kishte përgjigje.
  9. Skema dërgon telefonat në Grupin «Sekretaret», ku klienti priti 12 sekonda.
  10. Në grup, thirren njëkohësisht 2 punonjës «Sekretari1» dhe «Sekretari2» dhe pas 12 sekondash përgjigjet punonjësi «Sekretari2». Përgjigjja në thirrje përsëritet në thirrjet prindërore. Pra, në grup përgjigj «Sekretari2», nga skema përgjigj «Sekretari2» dhe në thirrjen nga linja e jashtme përgjigj «Sekretari2».

Ruajtja e informacionit për çdo operacion dhe nivelin e tij do të lejojë të krijoni raportet lehtësisht. Raporti për menunë e zërit do të ndihmojë të zbulohet sa ndihmon ose pengon. Të krijoni një raport mbi thirrjet e humbura nga punonjësit duke marrë parasysh se thirrja u kap dhe prandaj nuk konsiderohet e humbur, dhe duke marrë parasysh se ishte një thirrje grupore, dhe dikush tjetër e mori më parë, kështu që gjithashtu thirrje nuk është e humbur.

Ky ruajtje informacioni do të lejojë të merret çdo grup veçmas dhe të përcaktohet sa efektiv është ai, të krijoni një grafik të thirrjeve të përgjigjura dhe të humbura nga grupi sipas orëve. Gjithashtu mund të kontrolloni sa shpesh lidhet me menaxherin përkatës, duke analizuar transferimet pas lidhjes me menaxherin.

Për të kryer hulumtime jo shumë të zakonshme, për shembull, sa shpesh numrat që nuk janë në bazë regjistrojnë numrin e duhur të shtesës ose sa përqind e thirrjeve dalëse janë përcjellje në celular.

Çfarë doli përfundimisht?

Për të mbajtur ATS nuk kërkohet një specialist, një administrator i zakonshëm e bën këtë - është provuar në praktikë.

Për përmirësime nuk nevojiten specialistë me kualifikim të lartë, mjafton njohuri në php, pasi tashmë janë shkruar module për protokollin sip, për radhë, për thirrjen e punonjësve dhe të tjera. Ka një klasë mbështetje për Asterisk. Programuesi për zhvillimin e modulit mund (dhe me të drejtë duhet) të thërrasë modulet tashmë të gatshme. Dhe njohuritë Asterisk nuk janë të nevojshme, nëse klienti kërkon të shtojë një faqe me ndonjë raport të ri. Por praktika tregon se programuesit e jashtëm edhe pse arrijnë me sukses, ndihen të paqëndrueshëm pa dokumentacion dhe komente të mira, prandaj ka ende për të bërë.

Modulet mund të:

  • krijojnë mundësi të reja për përpunimin e thirrjeve,
  • shtojnë blloqe të reja në ndërfaqen web,
  • të trashëgojnë nga ndonjë nga modulet ekzistuese, të rikrijojnë funksionet dhe ta zëvendësojnë ose të jenë thjesht një kopje e modifikuar,
  • shtojnë cilësimet e tyre në shabllonin e cilësimeve të modulet e tjera dhe shumë më tepër.

Cilësimet e ATS përmes API. Siç u përmend më lart, të gjitha cilësimet ruhen në bazë dhe lexohen në momentin e thirrjes, prandaj përmes API mund të ndryshoni të gjitha cilësimet e ATS. Në thirrjen API nuk rindërtohet konfigurimi dhe nuk rinisin modulet, kështu që nuk ka rëndësi sa shumë cilësime dhe punonjësit keni. Kërkesat API ekzekutohen shpejt dhe nuk bllokojnë njëri-tjetrin.

ATS ruan të gjitha operacionet kryesore me thirrjet me kohëzgjatjet (pritjes / bisedës), niveli dhe në terminologjinë e ATS (punonjësi, grupi, linja e jashtme, jo kanali, numri). Kjo lejon ndërtimin e raporteve të ndryshme për klientë të caktuar dhe pjesa më e madhe e punës është krijimi i një ndërfaqeje të përshtatshme.

Çfarë do ndodhi më pas do ta tregojë koha. Ka ende shumë detaje që duhet rregulluar, ka ende shumë plane, por nga krijimi i versionit të 3-të ka kaluar një vit dhe tani mund të themi se ideja funksionon. Disavantazhi kryesor i versionit të 3-të janë burimet harduerike, por për lehtësinë e zhvillimit zakonisht duhet të paguhet kështu.

Burimi: habr.com

Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS 🔥 Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS | ProHoster