Integration af Asterisk og Bitrix24

Integration af Asterisk og Bitrix24
Der er forskellige muligheder for at integrere IP-PBX Asterisk og CRM Bitrix24 på netværket, men vi besluttede alligevel at skrive vores egen.

Med hensyn til funktionalitet er alt standard:

  • Ved at klikke på et link med en klients telefonnummer i Bitrix24 forbinder Asterisk det interne nummer på den bruger, på hvis vegne klikket blev foretaget, med klientens telefonnummer. I Bitrix24 optages en optagelse af opkaldet, og ved afslutningen af ​​opkaldet trækkes en optagelse af samtalen op.
  • Asterisk modtager et opkald udefra - i Bitrix24-grænsefladen viser vi klientkortet til den medarbejder, til hvis nummer dette opkald kom.
    Hvis der ikke er en sådan klient, åbner vi kortet for at oprette et nyt kundeemne.
    Så snart opkaldet er afsluttet, afspejler vi dette på kortet og trækker en optagelse af samtalen frem.

Under klippet fortæller jeg dig, hvordan du sætter alt op for dig selv og giver dig et link til github - ja, ja, tag det og brug det!

Generel beskrivelse

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

Anvendte teknologier og tjenester

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

forudindstilling

På en server med Asterisk skal du installere en webserver (for os er det nginx+php-fpm), supervisor og git.

Installationskommando (CentOS):

yum install nginx php-fpm supervisor git

Vi går til den mappe, der er tilgængelig for webserveren, trækker applikationen fra Git og indstiller de nødvendige rettigheder til mappen:


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

Lad os derefter konfigurere nginx, vores config er placeret i

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

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

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


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

    listen 443 ssl http2;
    server_name pbx.vistep.ru;
    resolver 8.8.8.8;
    ssl_stapling on;
    ssl on;
    ssl_certificate /etc/letsencrypt/live/pbx.vistep.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/pbx.vistep.ru/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; # запрет для скрытых файлов
        }

        location ~* /(?:uploads|files)/.*.php$ {
                deny all; # запрет для загруженных скриптов
        }

        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; # кеширование статики
        }

	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 vil lade parsing af konfigurationen, sikkerhedsproblemer, få et certifikat og endda vælge en webserver uden for artiklens rammer - der er skrevet meget om dette. Applikationen har ingen begrænsninger, den fungerer over både http og https.

Vi bruger https, lad os kryptere certifikatet.

Hvis du gjorde alt rigtigt, så ved at klikke på linket skulle du se noget som dette

Integration af Asterisk og Bitrix24

Opsætning af Bitrix24

Lad os oprette to webhooks.

Indgående webhook.

Under administratorkontoen (med id 1), følg stien: Applications -> Webhooks -> Add webhook -> Incoming webhook

Integration af Asterisk og Bitrix24

Udfyld parametrene for den indgående webhook som på skærmbillederne:

Integration af Asterisk og Bitrix24

Integration af Asterisk og Bitrix24

Og klik på Gem.

Efter at have gemt, vil Bitrix24 give URL'en på den indgående webhook, for eksempel:

Integration af Asterisk og Bitrix24

Gem din version af URL'en uden den endelige /profil/ - den vil blive brugt i applikationen til at arbejde med indgående opkald.

jeg har det https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/

Udgående webhook.

Applikationer -> Webhooks -> Tilføj webhook -> Udgående webhook

Detaljer er igen på skærmbillederne:

Integration af Asterisk og Bitrix24

Integration af Asterisk og Bitrix24

Gem og modtag godkendelseskoden

Integration af Asterisk og Bitrix24

jeg har det xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6. Du skal også kopiere det til dig selv; du skal bruge det til at foretage udgående opkald.

Vigtigt!

Et SSL-certifikat skal konfigureres på Bitrix24-serveren (du kan bruge letsencrypt), ellers vil Bitrix-api'et ikke fungere. Hvis du har en cloud-version, skal du ikke bekymre dig - den har allerede ssl.

Vigtigt!

Feltet "Processor Address" skal indeholde en adresse, der er tilgængelig fra internettet!

Og som en sidste touch, lad os installere vores CallMeOut som et program til at foretage opkald (så når du klikker på nummeret på PBX, vil kommandoen til at starte opkaldet flyve væk).

I menuen, vælg: Mere -> Telefoni -> Mere -> Indstillinger, indstil i "Standard udgående opkaldsnummer" Applikation: CallMeOut og klik på "Gem"

Integration af Asterisk og Bitrix24

Opsætning af stjerne

For vellykket interaktion mellem Asterisk og Bitrix24 skal vi tilføje AMI-brugeren callme til 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

Dernæst er der flere tricks, der skal implementeres via dialplan (for os er dette extensions.ael).

Jeg giver hele filen, og så giver jeg en forklaring:

globals {
    WAV=/var/www/pbx.vistep.ru/callme/records/wav; //Временный каталог с WAV
    MP3=/var/www/pbx.vistep.ru/callme/records/mp3; //Куда выгружать mp3 файлы
    URLRECORDS=https://pbx.vistep.ru/callme/records/mp3;
    RECORDING=1; // Запись, 1 - включена.
};

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()); // выставляем CallerID если узнали его у Битрикс24
        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 already was set ===));  
}

}


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 samtaleoptagelsesfilerne, ifølge hvilken Bitrix24 trækker dem ind i kontaktkortet.

Dernæst er vi interesserede i makromakroen optagelse.

Her vil vi, udover at optage samtaler, indstille variablen FullFname.

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

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

Lad os analysere det 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 sige, at vi ringer til 89991234567, først og fremmest kommer vi her:

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

de der. Samtaleoptagelsesmakroen kaldes, og de nødvendige variabler indstilles.

Næste

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

Vi registrerer, hvem der indledte opkaldet, og optager starttidspunktet for opkaldet.

Og efter dens afslutning, i en særlig sammenhæng 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});
}

deaktiver adgang til CDR-tabellen for dette lokalnummer (det er ikke nødvendigt der), indstil sluttidspunktet for opkaldet, beregn varigheden, hvis resultatet af opkaldet ikke er kendt - indstil (variabel CallMeDISPOSITION) og, det sidste trin, send alt til Bitrix via systemkrøllen.

Og lidt mere magi - et indgående opkald:

888999 => {
	&recording(${CALLERID(number)},${EXTEN});
        Answer();
        ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp()); // выставляем CallerID если узнали его у Битрикс24
        Set(CallStart=${STRFTIME(epoch,,%s)}); // начинаем отсчет времени звонка
        Queue(Q1,tT);
        Set(CallMeDISPOSITION=${CDR(disposition)}); 
        Hangup();
        }

Her er vi kun interesseret i én linje.

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

Hun beder PBX'en om at installere Opkalds-id (navn) lig med variabel CallMeCallerIDName.

Selve CallMeCallerIDName-variablen indstilles igen af ​​CallMe-applikationen (hvis Bitrix24 har et fulde navn til den, der ringer op, skal du indstille det som Opkalds-id (navn), nej - vi gør ikke noget).

Opsætning af applikationen

Programindstillingsfil - /var/www/pbx.vistep.ru/config.php

Beskrivelse af applikationsparametre:

  • CallMeDEBUG — hvis 1, så vil alle hændelser behandlet af applikationen blive skrevet til logfilen, 0 — vi skriver ikke noget
  • tech - SIP/PJSIP/IAX/etc
  • authToken — Bitrix24-autorisationstoken, udgående webhook-autorisationskode
  • bitrixApiUrl — URL på den indgående webhook, uden profil/
  • udvidelser — liste over eksterne numre
  • sammenhæng — kontekst for at starte et opkald
  • listener_timeout — hastighed af hændelsesbehandling fra stjerne
  • stjerne — et array med indstillinger for tilslutning til stjernen:
  • host — ip eller værtsnavn på stjerneserveren
  • Ordningen — forbindelsesdiagram (tcp://, tls://)
  • port - Havn
  • brugernavn - Brugernavn
  • hemmelighed - adgangskode
  • connect_timeout — timeout for forbindelsen
  • read_timeout - læse timeout

eksempel på indstillingsfil:

 <?php
return array(

        'CallMeDEBUG' => 1, // дебаг сообщения в логе: 1 - пишем, 0 - не пишем
        'tech' => 'SIP',
        'authToken' => 'xcrp2ylhzzd2v43cmfjqmkvrgrcbkni6', //токен авторизации битрикса
        'bitrixApiUrl' => 'https://b24-xsynia.bitrix24.ru/rest/1/7eh61lh8pahw0fwt/', //url к api битрикса (входящий вебхук)
        'extentions' => array('888999'), // список внешних номеров, через запятую
        'context' => 'dial_out', //исходящий контекст для оригинации звонка
        'asterisk' => array( // настройки для подключения к астериску
                    'host' => '10.100.111.249',
                    'scheme' => 'tcp://',
                    'port' => 5038,
                    'username' => 'callme',
                    'secret' => 'JD3clEB8_f23r-3ry84gJ',
                    'connect_timeout' => 10000,
                    'read_timeout' => 10000
                ),
        'listener_timeout' => 300, //скорость обработки событий от asterisk

);

Supervisor opsætning

Supervisor bruges til at starte hændelseshåndteringsprocessen fra Asterisk CallMeIn.php, som overvåger indgående opkald og interagerer med Bitrix24 (vis kort, skjul kort osv.).

Indstillingsfil, 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 applikationen:

supervisorctl start callme
supervisorctl restart callme

Visning af applikationens driftsstatus:

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

Konklusion

Det viste sig at være ret kompliceret, men jeg er sikker på, at en erfaren administrator vil være i stand til at implementere det og glæde sine brugere.

Som lovet, link til github.

Spørgsmål, forslag - læg dem venligst i kommentarerne. Også, hvis du er interesseret i, hvordan udviklingen af ​​denne integration gik, så skriv, og i den næste artikel vil jeg forsøge at afsløre alt mere detaljeret.

Kilde: www.habr.com

Tilføj en kommentar