Integration af Asterisk og Bitrix24

Integration af Asterisk og Bitrix24
Der er forskellige muligheder for integration af IP-PBX Asterisk og CRM Bitrix24, men vi har alligevel besluttet at skrive vores egen.

Funktionaliteten er standard:

  • Ved at klikke pĂ„ linket med kundens telefonnummer i Bitrix24, forbinder Asterisk brugerens interne nummer, som dette klik blev udfĂžrt fra, med kundens telefonnummer. I Bitrix24 registreres der en optegnelse af opkaldet, og efter opkaldets afslutning hentes optagelsen af samtalen.
  • Asterisk modtager et opkald udefra — i Bitrix24 viser vi kundekortet til den medarbejder, hvis nummer dette opkald kom til.
    Hvis kunden ikke findes, Äbner vi kortet til oprettelse af et nyt lead.
    NÄr opkaldet er afsluttet, afspejler vi dette i kortet og henter optagelsen af samtalen.

Nedenfor vil jeg fortélle, hvordan man opsétter det selv og give et link til GitHub — ja, tag det endelig og gþr brug af det!

Generel beskrivelse

Vi har kaldt vores integration CallMe. CallMe er en lille webapplikation skrevet i PHP.

Brugte teknologier og tjenester

  • PHP 5.6
  • PHP AMI-bibliotek
  • Composer
  • Nginx + php-fpm
  • supervisor
  • AMI (Asterisk Manager Interface)
  • Bitrix-webhooks (forenklet REST API-implementering)

Forudkonfiguration

PĂ„ serveren med Asterisk skal der installeres en webserver (vi bruger nginx+php-fpm), supervisor og git.

Kommandoen til installation (CentOS):

yum install nginx php-fpm supervisor git

GÄ til den mappe, der er tilgÊngelig for webserveren, trÊk applikationen fra git og sÊt de nÞdvendige rettigheder pÄ mappen:


cd /var/www
git clone https://github.com/ViStepRU/callme.git
chown nginx. -R callme/

DernĂŠst konfigurerer vi nginx, vores konfigurationsfil ligger i

/etc/nginx/conf.d/pbx.vistep.ru.conf

server {
	server_name www.pbx.vistep.dk pbx.vistep.dk;
	listen *:80;
	rewrite ^  https://pbx.vistep.dk$request_uri? permanent;
}

server {
#        listen *:80;
#	server_name pbx.vistep.dk;


	access_log /var/log/nginx/pbx.vistep.dk.access.log main;
        error_log /var/log/nginx/pbx.vistep.dk.error.log;

    listen 443 ssl http2;
    server_name pbx.vistep.dk;
    resolver 8.8.8.8;
    ssl_stapling on;
    ssl on;
    ssl_certificate /etc/letsencrypt/live/pbx.vistep.dk/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/pbx.vistep.dk/privkey.pem;
    ssl_dhparam /etc/nginx/certs/dhparam.pem;
    ssl_session_timeout 24h;
    ssl_session_cache shared:SSL:2m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers kEECDH+AES128:kEECDH:kEDH:-3DES:kRSA+AES128:kEDH+3DES:DES-CBC3-SHA:!RC4:!aNULL:!eNULL:!MD5:!EXPORT:!LOW:!SEED:!CAMELLIA:!IDEA:!PSK:!SRP:!SSLv2;
    ssl_prefer_server_ciphers on;
    add_header Strict-Transport-Security "max-age=31536000;";
    add_header Content-Security-Policy-Report-Only "default-src https:; script-src https: 'unsafe-eval' 'unsafe-inline'; style-src https: 'unsafe-inline'; img-src https: data:; font-src https: data:; report-uri /csp-report";
	
	root /var/www/callme;
	index  index.php;
        location ~ /.{
                deny all; # Forbud mod skjulte filer
        }

        location ~* /(?:uploads|files)/.*.php$ {
                deny all; # Forbud mod uploadede scripts
        }

        location ~* ^.+.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
                access_log off;
                log_not_found off;
                expires max; # Cache statiske filer
        }

	location ~ .php {
		root /var/www/callme;
		index  index.php;
		fastcgi_pass unix:/run/php/php5.6-fpm.sock;
	#	fastcgi_pass 127.0.0.1:9000;
		fastcgi_index index.php;
		fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
		include /etc/nginx/fastcgi_params;
		}
}

Jeg efterlader konfiguration, sikkerhedsspĂžrgsmĂ„l, certifikatgenerering og valg af webserver uden for denne artikel — der er allerede skrevet meget om det. Applikationen har ingen begrĂŠnsninger, den fungerer bĂ„de via http og https.

Vi bruger https, certifikat fra let’s encrypt.

Hvis du har gjort alt korrekt, skal du ved at fĂžlge linket se noget lignende.

Integration af Asterisk og Bitrix24

Konfiguration af Bitrix24

Lad os oprette to webhooks.

IndgÄende webhook.

Log ind med administratoraccount (id 1) og gÄ til: Applikationer -> Webhooks -> TilfÞj webhook -> IndgÄende webhook

Integration af Asterisk og Bitrix24

Udfyld parametrene for den indgÄende webhook som vist i skÊrmbillederne:

Integration af Asterisk og Bitrix24

Integration af Asterisk og Bitrix24

Og tryk pÄ gem.

Efter gemmelsen vil Bitrix24 give dig URL'en til den indgÄende webhook, for eksempel:

Integration af Asterisk og Bitrix24

Gem din version af URL'en uden den afsluttende /profile/ — den vil blive brugt i applikationen til at hĂ„ndtere indgĂ„ende opkald.

For mig er det https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/

UdgÄende webhook.

Applikationer -> Webhooks -> TilfÞj webhook -> UdgÄende webhook

Detaljerne findes igen i skĂŠrmbillederne:

Integration af Asterisk og Bitrix24

Integration af Asterisk og Bitrix24

Gem og fÄ autorisationskoden

Integration af Asterisk og Bitrix24

For mig er det xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. Denne skal ogsÄ kopieres, da den er nÞdvendig for at foretage udgÄende opkald.

Vigtigt!

PĂ„ Bitrix24-serveren skal SSL-certifikatet vĂŠre konfigureret (letsencrypt kan bruges), ellers vil Bitrix API ikke fungere. Hvis du har en cloud-version, behĂžver du ikke bekymre dig — der er allerede SSL.

Vigtigt!

I feltet "Handler URL" skal du angive en adresse, der er tilgĂŠngelig fra internettet!

Og som det sidste trin installerer vi vores CallMeOut som en applikation til at foretage opkald (sÄ nÄr du klikker pÄ et nummer, sendes en kommando til ACD for at initiere opkaldet).

I menuen vÊlger vi: Flere -> Telefonisystem -> Flere -> Indstillinger, sÊtter "Standardnummer til udgÄende opkald" til App: CallMeOut og klikker pÄ "Gem".

Integration af Asterisk og Bitrix24

Konfiguration af Asterisk

For at sikre, at Asterisk og Bitrix24 fungerer sammen, skal vi tilfĂžje AMI-brugeren callme i manager.conf:

[callme]
secret = JD3clEB8_f23r-3ry84gJ
deny = 0.0.0.0/0.0.0.0
permit = 127.0.0.1/255.255.255.0
permit= 10.100.111.249/255.255.255.255
permit = 192.168.254.0/255.255.255.0
read = system,call,log,verbose,agent,user,config,dtmf,reporting,cdr,dialplan
write = system,call,agent,log,verbose,user,config,command,reporting,originate

Der er nogle tricks, som skal implementeres gennem dialplan (i vores tilfĂŠlde extensions.ael).

Her er hele filen, og jeg vil give forklaringer bagefter:

globals {
    WAV=\/var\/www\/pbx.vistep.ru\/callme\/records\/wav; \/\/Midlertidig katalog med WAV
    MP3=\/var\/www\/pbx.vistep.ru\/callme\/records\/mp3; \/\/Hvor mp3-filerne gemmes
    URLRECORDS=https:\/\/pbx.vistep.ru\/callme\/records\/mp3;
    RECORDING=1; \/\/ Optagelse, 1 - aktiveret.
};

macro recording(calling,called) {
        if ("${RECORDING}" = "1"){
              Set(fname=${UNIQUEID}-${STRFTIME(${EPOCH},,%Y-%m-%d-%H_%M)}-${calling}-${called});
	      Set(datedir=${STRFTIME(${EPOCH},,%Y\/%m\/%d)});
	      System(mkdir -p ${MP3}\/${datedir});
	      System(mkdir -p ${WAV}\/${datedir});
              Set(monopt=nice -n 19 \/usr\/bin\/lame -b 32  --silent "${WAV}\/${datedir}\/${fname}.wav"  "${MP3}\/${datedir}\/${fname}.mp3" && rm -f "${WAV}\/${fname}.wav" && chmod o+r "${MP3}\/${datedir}\/${fname}.mp3");
	      Set(FullFname=${URLRECORDS}\/${datedir}\/${fname}.mp3);
              Set(CDR(filename)=${fname}.mp3);
	      Set(CDR(recordingfile)=${fname}.wav);
              Set(CDR(realdst)=${called});
              MixMonitor(${WAV}\/${datedir}\/${fname}.wav,b,${monopt});

       };
};


context incoming {
888999 => {
	&recording(${CALLERID(number)},${EXTEN});
        Answer();
        ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); \/\/ SĂŠtter CallerID hvis vi kender det fra Bitrix24
        Set(CallStart=${STRFTIME(epoch,,%s)});
        Queue(Q1,tT);
        Set(CallMeDISPOSITION=${CDR(disposition)});
        Hangup();
        }

h => {
    Set(CDR_PROP(disable)=true);
    Set(CallStop=${STRFTIME(epoch,,%s)});
    Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)});
    ExecIF(${ISNULL(${CallMeDISPOSITION})}?Set(CallMeDISPOSITION=${CDR(disposition)}):NoOP(=== CallMeDISPOSITION var allerede sat ===));  
}

}


context default {

_X. => {
        Hangup();
        }
};


context dial_out {

_[1237]XX => {
	&recording(${CALLERID(number)},${EXTEN});
        Set(__CallIntNum=${CALLERID(num)})
	Set(CallStart=${STRFTIME(epoch,,%s)});
        Dial(SIP\/${EXTEN},,tTr);
        Hangup();
        }

_11XXX => {
	&recording(${CALLERID(number)},${EXTEN});
	Set(CallStart=${STRFTIME(epoch,,%s)});
	Set(__CallIntNum=${CALLERID(num)});
        Dial(SIP\/${EXTEN:2}@toOurAster,,t);
        Hangup();
        }

_. => {
	&recording(${CALLERID(number)},${EXTEN});
        Set(__CallIntNum=${CALLERID(num)})
	Set(CallStart=${STRFTIME(epoch,,%s)});
	Dial(SIP\/${EXTEN}@toOurAster,,t);
	Hangup();
        }

h => {
        Set(CDR_PROP(disable)=true);
        Set(CallStop=${STRFTIME(epoch,,%s)});
        Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)});
	if(${ISNULL(${CallMeDISPOSITION})}) {
          Set(CallMeDISPOSITION=${CDR(disposition)});
        }
	System(curl -s http:\/\/pbx.vistep.ru\/CallMeOut.php --data action=sendcall2b24 --data call_id=${CallMeCALL_ID} --data-urlencode FullFname=${FullFname} --data CallIntNum=${CallIntNum} --data CallDuration=${CallMeDURATION} --data-urlencode CallDisposition=${CallMeDISPOSITION});
}

};

Lad os starte fra begyndelsen: direktivet globals.

Variabel URLRECORDS gemmer URL'en til optagelsesfiler, som Bitrix24 vil trĂŠkke ind i kontaktkortet.

DernĂŠst er vi interesserede i makroen recording.

Her, udover optagelse af samtaler, sĂŠtter vi variablen FullFname.

Set(FullFname=${URLRECORDS}\/${datedir}\/${fname}.mp3);

Den gemmer den fulde URL til den specifikke fil (makroen kaldes overalt).

Lad os gennemgÄ udgÄende opkald:

_. => {
	&recording(${CALLERID(number)},${EXTEN});
        Set(__CallIntNum=${CALLERID(num)})
	Set(CallStart=${STRFTIME(epoch,,%s)});
	Dial(SIP/${EXTEN}@toOurAster,,t);
	Hangup();
        }

h => {
        Set(CDR_PROP(disable)=true);
        Set(CallStop=${STRFTIME(epoch,,%s)});
        Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)});
	if(${ISNULL(${CallMeDISPOSITION})}) {
          Set(CallMeDISPOSITION=${CDR(disposition)});
        }
	System(curl -s http://pbx.vistep.ru/CallMeOut.php --data action=sendcall2b24 --data call_id=${CallMeCALL_ID} --data-urlencode FullFname=${FullFname} --data CallIntNum=${CallIntNum} --data CallDuration=${CallMeDURATION} --data-urlencode CallDisposition=${CallMeDISPOSITION});
}

Lad os antage, at vi ringer til 89991234567, fĂžrst ender vi her:

&recording(${CALLERID(number)},${EXTEN});

dvs. makroen til optagelse af samtalen kaldes og de nĂždvendige variabler indstilles.

NĂŠste

        Set(__CallIntNum=${CALLERID(num)})
	Set(CallStart=${STRFTIME(epoch,,%s)});

vi registrerer, hvem der initierede opkaldet, og registrerer tiden for opkaldets start.

Og ved dens afslutning, i en specifik kontekst h

h => {
        Set(CDR_PROP(disable)=true);
        Set(CallStop=${STRFTIME(epoch,,%s)});
        Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)});
	if(${ISNULL(${CallMeDISPOSITION})}) {
          Set(CallMeDISPOSITION=${CDR(disposition)});
        }
	System(curl -s http://pbx.vistep.ru/CallMeOut.php --data action=sendcall2b24 --data call_id=${CallMeCALL_ID} --data-urlencode FullFname=${FullFname} --data CallIntNum=${CallIntNum} --data CallDuration=${CallMeDURATION} --data-urlencode CallDisposition=${CallMeDISPOSITION});
}

vi deaktiverer optagelsen i CDR-tabellen for denne extension (det er ikke nÞdvendigt der), indstiller tidspunkterne for opkaldets afslutning, beregner varigheden, hvis resultaterne af opkaldet er ukendte, sÄ sÊttes variablen CallMeDISPOSITION) og som det sidste skridt sender vi alt til Bitrix via systemets curl.

Og lidt mere magi - indgÄende opkald:

888999 => {
	&recording(${CALLERID(number)},${EXTEN});
        Answer();
        ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // sĂŠtter CallerID, hvis vi genkender det fra Bitrix24
        Set(CallStart=${STRFTIME(epoch,,%s)}); // starter tidtagning for opkaldet
        Queue(Q1,tT);
        Set(CallMeDISPOSITION=${CDR(disposition)}); 
        Hangup();
        }

Her er vi kun interesseret i én linje.

ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp());

Den instruerer PBX'en til at indstille CallerID(name) lig med variablen CallMeCallerIDName.

Selve variablen CallMeCallerIDName, i sin tur, indstilles af applikationen CallMe (hvis der er et navn i Bitrix24 for det ringende nummer - indstilles som CallerID(name), hvis ikke - gĂžr vi ikke noget).

Indstillinger for applikationen

Applikationens indstillingsfil - /var/www/pbx.vistep.ru/config.php

Beskrivelse af applikationens parametre:

  • CallMeDEBUG — hvis 1, sĂ„ vil alle begivenheder, der behandles af applikationen, blive skrevet til logfilen, 0 - ingen optagelse
  • tech — SIP/PJSIP/IAX/etc
  • authToken — Bitrix24 autorisationstoken, autorisationskode for udgĂ„ende webhook
  • bitrixApiUrl — URL for indgĂ„ende webhook, uden profile/
  • extentions — liste over eksterne numre
  • context — kontekst for opkaldsoprindelse
  • listener_timeout — hastigheden for behandling af begivenheder fra Asterisk
  • asterisk — array med indstillinger for forbindelse til Asterisk:
  • host — ip eller hostname for Asterisk-serveren
  • scheme — forbindelsesskema (tcp://, tls://)
  • port — port
  • brugernavn — brugernavn
  • hemmelig — adgangskode
  • connect_timeout — forbindelse timeout
  • read_timeout — lĂŠse timeout

eksempel pÄ konfigurationsfil:

 1, // debugs beskeder i loggen: 1 - vi logger, 0 - vi logger ikke
        'tech' => 'SIP',
        'authToken' => 'xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6', //authorization token for Bitrix
        'bitrixApiUrl' => 'https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/', //URL til Bitrix API (indgÄende webhook)
        'extentions' => array('888999'), // liste over eksterne numre, adskilt af komma
        'context' => 'dial_out', // udgÄende kontekst for opkaldsoprindelse
        'asterisk' => array( // indstillinger for forbindelse til Asterisk
                    'host' => '10.100.111.249',
                    'scheme' => 'tcp://',
                    'port' => 5038,
                    'username' => 'callme',
                    'secret' => 'JD3clEB8_f23r-3ry84gJ',
                    'connect_timeout' => 10000,
                    'read_timeout' => 10000
                ),
        'listener_timeout' => 300, // hastigheden for behandling af begivenheder fra Asterisk

);

Konfiguration af supervisor

Supervisor bruges til at starte proceshandleren for begivenheder fra Asterisk CallMeIn.php, som overvÄger indgÄende opkald og interagerer med Bitrix24 (viser kort, skjuler kort osv.).

Konfigurationsfil, der skal oprettes:

/etc/supervisord.d/callme.conf

[program:callme]
command=/usr/bin/php CallMeIn.php
directory=/var/www/pbx.vistep.ru
autostart=true
autorestart=true
startretries=5
stderr_logfile=/var/www/pbx.vistep.ru/logs/daemon.log
stdout_logfile=/var/www/pbx.vistep.ru/logs/daemon.log

Start og genstart af applikationen:

supervisorctl start callme
supervisorctl restart callme

vis applikationens driftsstatus:

supervisorctl status callme
callme                           RUNNING   pid 11729, uptime 17 days, 16:58:07

Konklusion

Det blev lidt kompliceret, men jeg er sikker pÄ, at en erfaren administrator kan implementere det og glÊde deres brugere.

Som lovet, link til GitHub.

SpĂžrgsmĂ„l, Ăžnsker – kontakt venligst i kommentarerne. Hvis du ogsĂ„ er interesseret i, hvordan denne integration blev udviklet, sĂ„ skriv, og jeg vil forsĂžge at uddybe det i en kommende artikel.

Kilde: habr.com

KĂžb pĂ„lidelig webhosting med DDoS-beskyttelse, VPS VDS-servere đŸ”„ KĂžb pĂ„lidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster