AmoCRM популярное облачное решение с более-менее нормальным вижетом для Asterisk.
Само-подписанный SSl сертификат годится только для тестов,
для продакшена ОБЯЗАТЕЛЬНО требуется доверенный сертификат веб сервера выписанный на ваше доменное имя.
Данное руководство дает справочную информацию о настройке и тестировании интеграции Asterisk и AmoCRM и предполагает, что вы имеете базовые знания о Linux и Asterisk.
Настройку можно разделить на 4 основных этапа:
Скрипт amocrm.php должен быть доступен снаружи сети. Таким образом, если сервер Asterisk находится за nat, вам потребуется открыть веб сервер на asterisk, для доступа извне.
Внешний адрес за которым находится Asterisk, должен быть указан как цель для используемого доменного имени.
Сертификат может быть выписан на доменное имя третьего уровня, например: asterisk.yourdomain.com.
Доменное имя должно быть назначено серверу Asterisk.
Несмотря на обширный текст, настройка данного решения довольно проста.
Большая часть материала посвящена тонкой доводке и возможно не потребуется.
Настройка AMI и AJAM
Со стороны Asterisk требуется только включить AJAM:
/etc/asterisk/manager.conf
[general]
enabled = yes
port = 5038
bindaddr = 0.0.0.0
webenabled = yes
httptimeout = 60
создать пользователя AMI для AmoCRM
[amocrm]
secret = PASSWORD
deny = 0.0.0.0/0.0.0.0
permit = 127.0.0.1/255.255.255.0
read = cdr,reporting,originate
write = reporting,originate
и включить встроенный http сервер
Во FreePBX:
FreePBX: Settings > advanced_settings
или в конфиге Asterisk:
/etc/asterisk/http.conf
[general]
enabled=yes
enablestatic=yes
bindaddr=0.0.0.0
bindport=8088
prefix=asterisk
Тест AJAM интерфейса
asterisk*CLI> http show status
HTTP Server Status:
Prefix: /asterisk
Server: Asterisk/13.2.0
Server Enabled and Bound to 0.0.0.0:8088
Enabled URI's:
/asterisk/httpstatus => Asterisk HTTP General Status
/asterisk/amanager => HTML Manager Event Interface w/Digest authentication
/asterisk/arawman => Raw HTTP Manager Event Interface w/Digest authentication
/asterisk/manager => HTML Manager Event Interface
/asterisk/rawman => Raw HTTP Manager Event Interface
/asterisk/static/... => Asterisk HTTP Static Delivery
/asterisk/amxml => XML Manager Event Interface w/Digest authentication
/asterisk/mxml => XML Manager Event Interface
/asterisk/ws => Asterisk HTTP WebSocket
Enabled Redirects:
None.
https://asterisk_ip:8088/asterisk/httpstatus?action=login&username=<ami_user>&secret=<ami_password>
https://asterisk_ip:8088/asterisk/rawman?action=login&username=<ami_user>&secret=<ami_password>
Response: Success
Message: Authentication accepted
Скрипт AmoCRM
AmoCRM получает данные от Asterisk через GET запросы к скрипту, который в свою очередь,
запрашивает данные у Астера через AJAM или AMI и SQL запросами к БД asteriskcdrdb.
Базовая конфигурация скрипта
Сначала вам потребуется задать параметры доступа к базе данных asteriskcdrdb,
префикс AJAM, а также путь к директории записей.
Рассмотрим обще-употребимый пример получения записей из FreePBX.
Записи по умолчанию расположены в директории:
/var/spool/asterisk/monitor/Год/Месяц/День
Создадим в веб директории в которой расположен скрипт мягкую ссылку на директорию записей Asterisk:
ln -s /var/spool/asterisk/monitor monitor
Чтобы затруднить доступ к директории запретите листениг в файле .htaccess
Options -Indexes
В этом случае ссылка в скрипте amocrm будет выглядеть так:
https://ваше_доменное_имя/веб_директория_скрипта/monitor/%Y/%m/%d/#
Приведенные ниже рассуждения и примеры о получении записей относятся к версии php скрипта из этой статьи. Возможно, у вас есть более актуальная версия, но общие положения должны быть верны.
На этапе первоначальной установки и конфигурации можно пропустить.
Для отображения записей в AmoCRM, возможно, потребуется модифицировать SQL запросы в скрипте:
Получение имени файла из базы данных asteriskcdrdb производится по запросу:
GET ../amocrm.php?GETFILE=1505491053.1619
где 1505491053.1619 UNIQUEID вызова.
Скрипт amocrm в свою очередь пытается получить имя файла из колонки recordingfile БД asteriskcdrdb и таблицы cdr следующим запросом:
SELECT calldate,recordingfile FROM cdr WHERE uniqueid= :uid
где uid это UNIQUEID из GET запроса.
Но по этому запросу БД может выдать несколько строк с совпадающим UNIQUEID и только в одной будет задано recordingfile
Например, в случае, если запись включена в настройках екстеншена, а вызов поступает сначала в группу или очередь, а только потом на екстеншен. Ситуация описана для FreePBX.
Нажмите, чтобы отобразить
+---------------------+-------------------------------------------------------------+
| calldate | recordingfile |
+---------------------+-------------------------------------------------------------+
| 2017-09-15 18:57:33 | |
| 2017-09-15 18:57:33 | |
| 2017-09-15 18:58:00 | external-02-666-20170915-185733-1505491053.1619.wav |
+---------------------+-------------------------------------------------------------+
В этом случае надо либо включить запись в настройках группы или очереди,
или, например, модифицировать зарос следующим образом, чтобы получать только одну, последнюю запись из БД.
SELECT calldate,recordingfile FROM cdr WHERE uniqueid= :uid order by calldate DESC limit 1
или
сохраним UNIQUEID в переменную $recfile:
$recfile = $_GET['GETFILE'];
а искать будем не по колонке uniqueid, а по recordingfile:
SELECT calldate, recordingfile FROM cdr WHERE recordingfile like '%$recfile%';
Данные CDR в БД AmoCRM передаются по запросу (каждые 40 минут):
GET .. /amocrm.php?_login=<AMI_LOGIN>&_secret=<AMI_PASSWORD>&_action=cdr&date_from=<дата_от>&date_to=<и_до>
По которому, в свою очередь, скрипт делает выборку из БД следующего вида:
SELECT calldate,src,dst,duration,billsec,uniqueid,recordingfile FROM cdr WHERE disposition=\'ANSWERED\' AND billsec>=:minsec AND calldate> :from AND calldate< :to
По данной выборке в БД AmoCRM будут попадать все вызовы включая местные.
Если вы хотите избавиться, например, от внутренних вызовов, то можно модифицировать запрос следующим образом. В приведенном примере отфильтрованы вызовы с номеров 100-199.
добавив следующее условие AND src NOT RLIKE "^1xx"
SELECT calldate, src,dst,duration,billsec,uniqueid,recordingfile FROM cdr WHERE disposition=\'ANSWERED\'
AND src NOT RLIKE "^1xx" AND billsec>=:minsec AND calldate> :from AND calldate< :to
И так далее по образу и подобию, по вашим условиям.
Скрипт AmoCRM
Расположите скрипт в веб директории сервера asterisk.
В приведенных ниже примерах скрипт расположен в корне - /var/www/html/amocrm.php,
но лучше разместить его в директории с неявным именем.
Например:
<?php
/*
amoCRM to asterisk integration.
mailto: info@asterisk-pbx.ru
Date: 21.09.2017
_____ _____ __ __
/ ____| __ \| \/ |
__ _ _ __ ___ ___ | | | |__) | \ / |
/ _` | '_ ` _ \ / _ \| | | _ /| |\/| |
| (_| | | | | | | (_) | |____| | \ \| | | |_
\__,_|_| |_| |_|\___/ \_____|_| \_\_| |_(_)
*/
ini_set('display_errors',0);
define('AC_HOST','localhost');
define('AC_PORT',8088);
define('AC_PREFIX','/aster/');
define('AC_TLS',false);
define('AC_DB_CS','mysql:host=localhost;port=3306;dbname=asteriskcdrdb');
define('AC_DB_UNAME','db_user');
define('AC_DB_UPASS','db_password');
define('AC_TIMEOUT',0.75);
define('AC_RECORD_PATH','https://hostname/amo_dir/monitor/%Y/%m/%d/#');
define('AC_TIME_DELTA',3); // hours. Ex. GMT+4 = 4
$db_cs=AC_DB_CS;
$db_u=!strlen(AC_DB_UNAME)?NULL:AC_DB_UNAME;
$db_p=!strlen(AC_DB_UPASS)?NULL:AC_DB_UPASS;
date_default_timezone_set('UTC');
if (AC_PORT<1) die('Please, configure settings first!'); // die if not
if (defined('AC_RECORD_PATH') AND !empty($_GET['GETFILE'])){
//get file. Do not check auth. (uniqueid is rather unique)
$p=AC_RECORD_PATH;
if (empty($p)) die('Error while getting file from asterisk (no path)');
try {
$dbh = new PDO($db_cs, $db_u, $db_p);
$sth = $dbh->prepare('SELECT calldate,recordingfile FROM cdr WHERE uniqueid= :uid order by calldate DESC limit 1');
$sth->bindValue(':uid',strval($_GET['GETFILE']));
$sth->execute();
$r = $sth->fetch(PDO::FETCH_ASSOC);
if ($r===false OR empty($r['recordingfile'])) die('Error while getting file from asterisk (no filename in select)');
$date=strtotime($r['calldate']);
$replace=array();
$replace['#']=$r['recordingfile'];
$dates=array('d','m','Y','y');
foreach ($dates as $d) $replace['%'.$d]=date($d,$date); // not a good idea!
$p=str_replace(array_keys($replace),array_values($replace),$p);
if (empty($_GET['noredirect'])) header('Location: '.$p);
die($p);
} catch (PDOException $e) {
die('Error while getting file from asterisk');
}
}
// filter parameters from _GET
foreach (array('login','secret','action') as $k){
if (empty($_GET['_'.$k])) die('NO_PARAMS');
$$k=strval($_GET['_'.$k]);
}
// trying to check accacess
$loginArr=array(
'Action'=>'Login',
'username'=>$login,
'secret'=>$secret,
// 'Events'=>'off',
);
$resp=asterisk_req($loginArr,true);
// problems? exiting
if ($resp[0]['response']!=='Success') answer(array('status'=>'error','data'=>$resp[0]));
//auth OK. Lets perform actions
if ($action==='status'){ // list channels status
$params=array( 'action'=>'status');
$resp=asterisk_req($params);
// report error of any
if ($resp[0]['response']!=='Success') answer(array('status'=>'error','data'=>$resp[0]));
// first an last chunks are useless
unset($resp[end(array_keys($resp))],$resp[0]);
// renumber keys for JSON
$resp=array_values($resp);
// report OK
answer(array('status'=>'ok','action'=>$action,'data'=>$resp));
}elseif ($action==='call'){ // originate a call
$params=array(
'action'=>'Originate',
'channel'=>'Local/'.$_GET['from'].'@from-internal',
'Exten'=>strval($_GET['to']),
'Context'=>'from-internal',
'priority'=>'1',
'Callerid'=>'"'.strval($_GET['as']).'" <'.intval($_GET['from']).'>',
'Async'=>'Yes',
// Not Implemented:
//'Callernumber'=>'150',
//'CallerIDName'=>'155',
);
$resp=asterisk_req($params,true);
if ($resp[0]['response']!=='Success') answer(array('status'=>'error','data'=>$resp[0]));
answer(array('status'=>'ok','action'=>$action,'data'=>$resp[0]));
} elseif ($action==='test_cdr'){ // test if DB connection params are OK.
if (!class_exists('PDO')) answer(array('status'=>'error','data'=>'PDO_NOT_INSTALLED')); // we use PDO for accessing mySQL pgSQL sqlite within same algorythm
try {
$dbh = new PDO($db_cs, $db_u, $db_p);
} catch (PDOException $e) {
answer(array('status'=>'error','data'=>$e->getMessage()));
}
answer(array('status'=>'ok','data'=>'connection ok'));
} elseif ($action==='cdr'){ // fetch call history
try {
$dbh = new PDO($db_cs, $db_u, $db_p);
foreach (array('date_from','date_to') as $k){
$v=doubleval( (!empty($_GET[$k]))?intval($_GET[$k]):0 );
if ($v<0) $v=time()-$v;
$$k=$v;
}
if ($date_from<time()-10*24*3600) $date_from=time()-7*24*3600; //retr. not more than 10d before
$date_from=($date_from?$date_from+AC_TIME_DELTA*3600:0); //default 01-01-1970
$date_to =($date_to ?$date_to +AC_TIME_DELTA*3600:time()+AC_TIME_DELTA*3600);//default now()
$sth = $dbh->prepare('SELECT calldate, src,dst,duration,billsec,uniqueid,recordingfile FROM cdr WHERE disposition=\'ANSWERED\' AND billsec>=:minsec AND calldate> :from AND calldate< :to');
// BETWEEN is illegal on some bcknds
header("X-REAL_DATE:" . gmdate('Y-m-d H:i:s',$date_from).'@'. gmdate('Y-m-d H:i:s',$date_to));
$sth->bindValue(':from', date('Y-m-d H:i:s',$date_from) );
$sth->bindValue(':to', date('Y-m-d H:i:s',$date_to));
$sth->bindValue(':minsec',!empty($_GET['minsec'])?$_GET['minsec']:5,PDO::PARAM_INT);
$sth->execute();
//$sth->debugDumpParams(); var_dump($sth->errorInfo());
$r = $sth->fetchAll(PDO::FETCH_ASSOC);
foreach ($r as $k=>$v) $r[$k]['calldate']=date('Y-m-d H:i:s',strtotime($v['calldate'])-AC_TIME_DELTA*3600);
answer(array('status'=>'ok','data'=>$r),true);
} catch (PDOException $e) {
answer(array('status'=>'error','data'=>$e->getMessage()),true);
}
} elseif ($action==='pop'){// fill test data. Maybe you will need it. Just comment line below.
die();
$dbh = new PDO($db_cs, $db_u, $db_p);
for ($i=0;$i<(int)$_GET['n'];$i++){
$array=array(
date('Y-m-d H:i:s',time()-rand(100,7*24*3600)),
'Auto <150>', 150,'791612345678','n/a','n/a','n/a','n/a','n/a',999, rand(7,999), 'ANSWERED',3,'',uniqid(),'','',''
);
$str=array();
foreach ($array as $v) $str[]="'{$v}'";
$str=implode(', ',$str);
$dbh->query("INSERT INTO cdr VALUES ({$str});");
}
}
/** MakeRequest to asterisk interfacees
* @param $params -- array of req. params
* @return array -- response
*/
function asterisk_req($params,$quick=false){
// lets decide if use AJAM or AMI
return !defined('AC_PREFIX')?ami_req($params,$quick):ajam_req($params);
}
/**
* Shudown function. Gently close the socket
*/
function asterisk_socket_shutdown(){ami_req(NULL);}
/*** Make request with AMI
* @param $params -- array of req. params
* @param bool $quick -- if we need more than action result
* @return array result of req
*/
function ami_req($params,$quick=false){
static $connection;
if ($params===NULL and $connection!==NULL) {
// close connection
fclose($connection);
return;
}
if ($connection===NULL){
$en=$es='';
$connection = fsockopen(AC_HOST, AC_PORT, $en, $es, 3);
// trying to connect. Return an error on fail
if ($connection) register_shutdown_function('asterisk_socket_shutdown');
else {$connection=NULL; return array(0=>array('response'=>'error','message'=>'socket_err:'.$en.'/'.$es));}
}
// building req.
$str=array();
foreach($params as $k=>$v) $str[]="{$k}: {$v}";
$str[]='';
$str=implode("\r\n",$str);
// writing
fwrite($connection,$str."\r\n");
// Setting stream timeout
$seconds=ceil(AC_TIMEOUT);
$ms=round((AC_TIMEOUT-$seconds)*1000000);
stream_set_timeout($connection,$seconds,$ms);
// reading respomse and parsing it
$str= ami_read($connection,$quick);
$r=rawman_parse($str);
//var_dump($r,$str);
return $r;
}
/*** Reads data from coinnection
* @param $connection -- active connection
* @param bool $quick -- should we wait for timeout or return an answer after getting command status
* @return string RAW response
*/
function ami_read($connection,$quick=false){
$str='';
do {
$line = fgets($connection, 4096);
$str .= $line;
$info = stream_get_meta_data($connection);
if ($quick and $line== "\r\n") break;
}while ($info['timed_out'] == false );
return $str;
}
/*** Echo`s data
* @param $array answer data
* @param bool $no_callback shold we output as JSON or use callback function
*/
function answer($array,$no_callback=false){
header('Content-type: text/javascript;');
if (!$no_callback) echo "asterisk_cb(".json_encode($array).');';
else echo json_encode($array);
die();
}
/** Parse RAW response
* @param $lines RAW response
* @return array parsed response
*/
function rawman_parse($lines){
$lines=explode("\n",$lines);
$messages=array();
$message=array();
foreach ($lines as $l){
$l=trim($l);
if (empty($l) and count($message)>0){ $messages[]= $message; $message=array(); continue;}
if (empty($l)) continue;
if (strpos($l,':')===false) continue;
list($k,$v)=explode(':',$l);
$k=strtolower(trim($k));
$v=trim($v);
if (!isset( $message[$k])) $message[$k]=$v;
elseif (!is_array( $message[$k])) $message[$k]=array( $message[$k],$v);
else $message[$k][]=$v;
}
if (count($message)>0) $messages[]= $message;
return $messages;
}
/** Make request via AJAM
* @param $params req. params
* @return array parsed resp.
*/
function ajam_req($params){
static $cookie;
// EveryRequest Ajam sends back a cookir, needed for auth handling
if ($cookie===NULL) $cookie='';
// make req. and store cookie
list($body,$cookie)= rq(AC_PREFIX.'rawman?'.http_build_query($params),$cookie);
// parse an answer
return rawman_parse($body);
}
/** make http req. to uri with cookie, parse resp and fetch a new cookie
* @param $url
* @param string $cookie
* @return array ($body,$newcookie)
*/
function rq($url,$cookie=''){
// get RAW data
$r=_rq($url,$cookie);
// divide in 2 parts
list($headersRaw,$body)=explode("\r\n\r\n",$r,2);
// parse headers
$headersRaw=explode("\r\n",$headersRaw);
$headers=array();
foreach ($headersRaw as $h){
if (strpos($h,':')===false) continue;
list($hname,$hv)=explode(":",$h,2);
$headers[strtolower(trim($hname))]=trim($hv);
}
// fetch cookie
if (!empty($headers['set-cookie'])){
$listcookies=explode(';',$headers['set-cookie']);
foreach ($listcookies as $c){
list($k,$v)=explode('=',trim($c),2);
if ($k=='mansession_id') $cookie=$v;
}
}
return array($body,$cookie);
}
/** mare a request to URI and return RAW resp or false on fail
* @param $url
* @param $cookie
* @return bool|string
*/
function _rq($url,$cookie){
$errno=$errstr="";
$fp = fsockopen(AC_HOST, AC_PORT, $errno, $errstr, 3);
if (!$fp) return false;
$out = "GET {$url} HTTP/1.1\r\n";
$out .= "Host: ".AC_HOST."\r\n";
if (!empty($cookie)) $out.="Cookie: mansession_id={$cookie}\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
$r='';
while (!feof($fp)) $r.=fgets($fp);
fclose($fp);
return $r;
}
Скрипт обрабатывает следующие запросы:
В зависимости от типа запросов они инициируется либо с IP-адреса сервера AmoCRM, либо с IP пользователя, работающего в AmoCRM.
Команда call позволяет инициировать соединение двух екстеншенов. Это функция потенциально опасна и требует дополнительных мер защиты. Например запретить обращение к веб серверу всем кроме AmoCRM и IP адресов с которых работают пользователи AmoCRM (что может быть проблематично, если пользователи работают из разных мест). Актуальный адрес с которого идут запросы AmoCRM на осень 2017 года: 88.212.249.27
Если вам не требуется данный функционал, просто запретите его использование в конфигурации пользователя amocrm в /etc/asterisk/manager.conf удалив опцию originate:
[amocrm]
secret = PASSWORD
deny = 0.0.0.0/0.0.0.0
permit = 127.0.0.1/255.255.255.0
read = cdr,reporting
write = reporting
Поверка работы скрипта:
status
https://host/amocrm.php?_login=<ami_user>&_secret=<ami_password>&_action=status
asterisk_cb({"status":"ok","action":"status","data":[]});
test_cdr
https://host/amocrm.php?_login=<ami_user>&_secret=<ami_password>&_action=test_cdr
asterisk_cb({"status":"ok","data":"connection ok"});
cdr
https://host/amocrm.php?_login=<ami_user>&_secret=<ami_password>&_action=cdr
{"calldate":"2015-03-11 12:38:16","src":"2274","dst":"3900","duration":"95","billsec":"87","uniqueid":"1426077496.1805","recordingfile":""},{"calldate":"2015-03-11
12:39:24","src":"3710","dst":"9xxxxxxxxx","duration":"74","billsec":"59","uniqueid":"1426077564.1817","recordingfile":""},{"calldate":"2015-03-11
12:41:56","src":"2776","dst":"3848","duration":"8","billsec":"8","uniqueid":"1426077716.1907","recordingfile":""},{"calldate":"2015-03-11
12:42:28","src":"2274","dst":"4321","duration":"7","billsec":"7","uniqueid":"1426077748.1923","recordingfile":""},{"calldate":"2015-03-11
12:42:59","src":"3892","dst":"2274","duration":"115","billsec":"113","uniqueid":"1426077779.1949","recordingfile":""},{"calldate":"2015-03-11
12:43:29","src":"4108","dst":"2207","duration":"71","billsec":"69","uniqueid":"1426077809.1957","recordingfile":""},{"calldate":"2015-03-11
12:45:06","src":"2776","dst":"3848","duration":"23","billsec":"16","uniqueid":"1426077906.2023","recordingfile":""},{"calldate":"2015-03-11
12:46:12","src":"2373","dst":"3914","duration":"239","billsec":"235","uniqueid":"1426077972.2055","recordingfile":""},{"calldate":"2015-03-11
call
amocrm.php?_login=<ami_login>&_secret=<ami_password>&_action=call&from=<TEL>&to=<TEL>
За обработку запроса call отвечает ниже приведенный код скрипта.
Возможно вам понадобится изменить имя исходящего контекста с from-internal,
на нужное вам.
}elseif ($action==='call'){ // originate a call
$params=array(
'action'=>'Originate',
'channel'=>'Local/'.$_GET['from'].'@from-internal',
'Exten'=>strval($_GET['to']),
'Context'=>'from-internal',
'priority'=>'1',
'Callerid'=>'"'.strval($_GET['as']).'" <'.intval($_GET['from']).'>',
'Async'=>'Yes',
);
Посмотреть запросы можно в логе ssl_access_log веб сервера:
tail -f /var/log/httpd/ssl_access_log
Настройка сертификата
Рассмотрим установку популярного сертификата от Comodo на веб сервер apache в CentOS 7.
Скачайте и распакуйте архив с сертификатами на сервер
AddTrustExternalCARoot.crt
your_domain_com.crt
COMODORSAAddTrustCA.crt
COMODORSADomainValidationSecureServerCA.crt
Создайте директорию для сертификатов:
mkdir /etc/pki/tls/cert
Создайте файл ключа
touch /etc/pki/tls/cert/your_domain_com.key
И скопируйте в него ключ.
Объедините файлы crt.
cat your_domain_com.crt COMODORSADomainValidationSecureServerCA.crt COMODORSAAddTrustCA.crt AddTrustExternalCARoot.crt > /etc/pki/tls/cert/ssl-bundle.crt
Включите ssl и укажите путь к созданным файлам /etc/httpd/conf.d/ssl.conf:
SSLEngine on
SSLCertificateKeyFile /etc/pki/tls/cert/your_domain_com.key
SSLCertificateFile /etc/pki/tls/cert/ssl-bundle.crt
Задайте серверу доменное имя /etc/sysconfig/network
HOSTNAME=your.domain.com
Добавьте имя в /etc/hosts:
внешний_IP your.domain.com hostname
Выполните команду hostname из командной строки
hostname your.domain.com
Сделайте рестарт httpd и network
AmoCRM вижет
Дополнительно
При помощи модуля CallerID Lookup вы может подставлять имена клиентов из AmoCRM в CALLERID(name) asterisk.
FreePBX: admin > CallerID Lookup Sources
FreePBX: Connectivity > Inbound Routes
Подключите созданный CallerID Lookup в нужном входящем маршруте:
Нажмите, чтобы отобразить
[root@asterisk ~]# cat /etc/asterisk/extensions_additional.conf | grep cidlookup
[cidlookup]
exten => cidlookup_1,1,Set(CURLOPT(httptimeout)=7)
exten => cidlookup_1,n,Set(CALLERID(name)=${CURL(https://api.opencnam.com/v2/phone/${CALLERID(num)}?format=pbx&ref=freepbx)})
exten => cidlookup_1,n,Set(current_hour=${STRFTIME(,,%Y-%m-%d %H)})
exten => cidlookup_1,n,Set(last_query_hour=${DB(cidlookup/opencnam_last_query_hour)})
exten => cidlookup_1,n,Set(total_hourly_queries=${DB(cidlookup/opencnam_total_hourly_queries)})
exten => cidlookup_1,n,ExecIf($["${last_query_hour}" != "${current_hour}"]?Set(DB(cidlookup/opencnam_total_hourly_queries)=0))
exten => cidlookup_1,n,ExecIf($["${total_hourly_queries}" = ""]?Set(DB(cidlookup/opencnam_total_hourly_queries)=0))
exten => cidlookup_1,n,Set(DB(cidlookup/opencnam_total_hourly_queries)=${MATH(${DB(cidlookup/opencnam_total_hourly_queries)}+1,i)})
exten => cidlookup_1,n,ExecIf($[${DB(cidlookup/opencnam_total_hourly_queries)} >= 60]?System(${ASTVARLIBDIR}/bin/opencnam-alert.php))
exten => cidlookup_1,n,Set(DB(cidlookup/opencnam_last_query_hour)=${current_hour})
exten => cidlookup_1,n,Return()
exten => cidlookup_2,1,GotoIf($[${DB_EXISTS(cidname/${CALLERID(num)})} = 1]?cidlookup,cidlookup_return,1)
exten => cidlookup_2,n,Set(CURLOPT(httptimeout)=7)
exten => cidlookup_2,n,Set(CALLERID(name)=${CURL(https://<ami_user>:<ami_password>@<amo_account>.amocrm.ru:443/private/acceptors/asterisk_new/?number=${CALLERID(num)}&USER_LOGIN=amo_user@mail.tld&USER_HASH=xxxxxxxxxxxxxxxxxxxxxxxxxxx)})
exten => cidlookup_2,n,Set(DB(cidname/${CALLERID(num)})=${CALLERID(name)})
exten => cidlookup_2,n,Return()
exten => cidlookup_return,1,ExecIf($["${DB(cidname/${CALLERID(num)})}" != ""]?Set(CALLERID(name)=${DB(cidname/${CALLERID(num)})}))
exten => cidlookup_return,n,Return()
;--== end of [cidlookup] ==--;
exten => _X.,n,Gosub(cidlookup,cidlookup_2,1())
[root@asterisk ~]# cat /etc/asterisk/extensions_override_freepbx.conf | grep cidlookup
[cidlookup]
include => cidlookup_custom
exten => cidlookup_2,1,Set(CALLERID(name)=${SHELL(wget -O - --quiet https://<amo_account>.amocrm.ru/private/acceptors/asterisk_new/?number=${CALLERID(num)}\&USER_LOGIN=amo_user@mail.tld\&USER_HASH=xxxxxxxxxxxxxxxxxxxxxxxxxx)})
exten => cidlookup_2,n,Return()
exten => cidlookup_return,1,ExecIf($["${DB(cidname/${CALLERID(num)})}" !=""]?Set(CALLERID(name)=${DB(cidname/${CALLERID(num)})}))
exten => cidlookup_return,n,Return()
ссылки по теме:
Описание функций
~~socialite~~