Вот еще интересная возможность
пропускать входящий звонок из транка через Stasis
- Код: Выделить всё
'000' => 1. Noop(****CRM******) [extensions.conf:164]
2. Answer() [extensions.conf:165]
3. Stasis(dialer) [extensions.conf:166]
4. HangUp() [extensions.conf:167]
таблица в базе
- Код: Выделить всё
CREATE TABLE `service_opers` (
`data_create` datetime DEFAULT CURRENT_TIMESTAMP,
`data_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`oper` varchar(80) DEFAULT NULL,
`await_calling_number` varchar(80) DEFAULT NULL,
`uncon_forward` text,
`busy_forward` text,
`timeout_forward` text
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Если в базе нашелся номер сотрудника то ${exten} = 'users',result[0].oper
отправляем в контекст 'users',
continue_d(ticket_stasis[rnd].ch_a,'users',result[0].oper,' ',' ');
если нет, то дальше.... ,
а у меня пока на playback 1000
continue_d(ticket_stasis[rnd].ch_a,'users','1000','','');
сам скрипт
- Код: Выделить всё
#!/usr/bin/env node
var ARI_HOST = '127.0.0.1';
var ARI_PORT = '8088';
var API_KEY = 'ariuser'+':'+ '123';
var APP_NAME = 'dialer';
var CONTEXT = 'users';
var TIMER = '30';
var FORMAT = 'alaw,ulaw';
var MEDIA = 'sound:paul_m';
//var MEDIA = 'sound:sh_11';
var MEDIA = 'sound:paul_bangles';
var SKIPMS = '3000';
var MIN =2000;
var MAX =2999;
var mysql = require('mysql');
var conn = mysql.createConnection({
host:'localhost',
port: '3306',
user:'crm',
password:'crm',
database:'crm',
charset: 'utf8'
});
conn.connect(function(err){
if (err) {
return console.error("Ошибка: " + err.message);
}
else{
console.log("Подключение к серверу MySQL успешно установлено");
}
});
var WebSocket = require('ws');
var WebSocketServer = require('ws').Server;
var request = require('request');
var ws = new WebSocket( 'ws://' + ARI_HOST + ':' + ARI_PORT + '/ari/events?app=' + APP_NAME + '&api_key=' + API_KEY );
var wss;
var moh_chan;
var uid ={};
var rnd ;
var ep;
var tmp;
var ticket_stasis = []; // объявление массива
class Ticket_Stasis{
//var trunk = new Array();
constructor(channel_id_b,channel_id_a,channel_name_a,calling_name,calling_number,called_number,trunk) {
this.bridge_number = channel_id_b - 1000;
this.channel_id_a = channel_id_a;
this.channel_name_a = channel_name_a;
this.calling_name = calling_name;
this.calling_number = calling_number
this.channel_id_b = channel_id_b;
this.called_number = called_number;
this.endp_tech =null;
this.playback_channel_id_a = channel_id_b + 4000;
this.playback_channel_id_b = channel_id_b + 7000;
this.snoop_channel_id_a = channel_id_b + 1000;
this.snoop_channel_id_b = channel_id_b + 2000;
this.ring_kpv_to_a =true;
this.ring_kpv_to_b =false;
this.hangup_from_a = false; // On
this.hangup_from_b = true; // Off
this.ticket_state = true;
this.trunk = trunk;
this.count_trying = 0;
this.client_info ='';
this.showcase = 'StasisStart';
}
get trunks() { return `${this.trunk}`; }
get ui() { return `${this.bridge_number}`; }
get ch_a() { return `${this.channel_id_a}`; }
get ch_b() { return `${this.channel_id_b}`; }
get playback_ch_a() { return `${this.playback_channel_id_a}`; }
get playback_ch_b() { return `${this.playback_channel_id_b}`; }
get snoop_ch_a() { return `${this.snoop_channel_id_a}`; }
get snoop_ch_b() { return `${this.snoop_channel_id_b}`; }
get cdn () { return `${this.called_number}`; }
get cgn () { return `${this.calling_number}`; }
get ring_kpv_goto_a () { return `${this.ring_kpv_to_a}`; }
get ring_kpv_goto_b () { return `${this.ring_kpv_to_b}`; }
get hangup_status_a () { return `${this.hangup_from_a}`; }
get hangup_status_b () { return `${this.hangup_from_b}`; }
get ticket_status() { return `${this.ticket_state}`; }
get info() { return `${this.client_info}`; }
get show_case() { return `${this.showcase}`; }
get cnt_try() { return `${this.count_trying}`; }
get ep() { return `${this.endp_tech}`; }
set ep(v) { this.endp_tech = v; }
set cnt_try(v) { this.count_trying = v; }
set trunks(v) { this.trunk = v; }
set ch_a(v) { this.channel_id_a = v; }
set ch_b(v) { this.channel_id_b = v; }
set ring_kpv_goto_a (v) { this.ring_kpv_to_a = v; }
set ring_kpv_goto_b (v) { this.ring_kpv_to_b = v; }
set hangup_status_a (v) { this.hangup_from_a = v; }
set hangup_status_b (v) { this.hangup_from_b = v; }
set ticket_status (v) { this.ticket_state=v; }
set info(v) { this.client_info=v; }
set show_case(v) { this.showcase=v; }
}
//////////////////////////
// обработчик входящих сообщений Asterisk
ws.on('open',function(){console.log('Connected to ARI');});
ws.on('error',function(e){console.log('ARI Connection error:',e);});
ws.on('message',function(d,flags){
var str = JSON.parse(d);
var ep;
//////////////////////////////////
//console.log(str);
////////////////////////////////
switch(str.type)
{
case "StasisStart":
//console.log(str);
console.log('Stasis start - Dialer');
if(str.channel.dialplan.exten == ""){break;}
rnd = get_uid();
ticket_stasis[rnd] = new Ticket_Stasis(rnd,str.channel.id,str.channel.name,str.channel.caller.name,str.channel.caller.number,str.channel.dialplan.exten,str.args);
// show_ticket(rnd);
ticket_stasis[rnd].show_case='StasisStart';
plus_bridge(ticket_stasis[rnd].ui);
plus_ch_to_bridge(ticket_stasis[rnd].ui,str.channel.id)
/////////////////////req service opers
var cgn =ticket_stasis[rnd].cgn;
if(cgn.startsWith('+')){
cgn=cgn.subString(1,cgn.length);}
var n = "'";
var n1 =n + '%' + cgn + '%' + n;
conn.query('SELECT * FROM service_opers where await_calling_number like' + n1
,function(error, result, fields){
//console.log(result[0].oper);
if(result != ''){
console.log(result[0].oper);
ticket_stasis[rnd].show_case='StasisEnd';
continue_d(ticket_stasis[rnd].ch_a,'users',result[0].oper,'','');
//delete ticket_stasis[rnd];
}else{
ticket_stasis[rnd].show_case='StasisEnd';
continue_d(ticket_stasis[rnd].ch_a,'users','1000','','');
//delete ticket_stasis[rnd];
}
});
/////////////////////////////END Mysql
break;
case "ChannelHangupRequest":
// console.log(str);
ticket_stasis.some(function(item, index, array) {
if(ticket_stasis[index].ch_a == 'timeout' ){
minus_bridge (ticket_stasis[index].ui);
//ticket_stasis[index].ticket_status=false;
//ticket_stasis[index].show_case='ChannelHangupRequest';
//wss.broadcast(JSON.stringify(ticket_stasis[index]));
delete ticket_stasis[index];
return;
}
if(ticket_stasis[index].ch_a == str.channel.id ){
//console.log('From A');
if(ticket_stasis[index].show_case != 'StasisStart'){
minus_ch(ticket_stasis[index].ch_b,'normal');}
minus_bridge (ticket_stasis[index].ui);
//ticket_stasis[index].ticket_status=false;
ticket_stasis[index].show_case='ChannelHangupRequest';
//wss.broadcast(JSON.stringify(ticket_stasis[index]));
delete ticket_stasis[index];
return;
}
//------------------------
if(ticket_stasis[index].ch_b == str.channel.id){
//if(ticket_stasis[index].ch_a!=null){}
minus_ch(ticket_stasis[index].ch_a,'normal');
minus_bridge (ticket_stasis[index].ui);
//ticket_stasis[index].ticket_status=false;
ticket_stasis[index].show_case='ChannelHangupRequest';
//wss.broadcast(JSON.stringify(ticket_stasis[index]));
delete ticket_stasis[index];
return;
}
})
break;
case "ChannelLeftBridge":break;
case "ChannelDestroyed":
break;
case "PlaybackStarted":break;
case "PlaybackFinished":break;
case "StasisEnd":
ticket_stasis.some(function(item, index, array) {
if(ticket_stasis[index].show_case == 'StasisEnd'){
minus_bridge(ticket_stasis[index].ui);
delete ticket_stasis[index];
}
});
break;
case "ChannelUserevent"://console.log(str);
break;
default: // console.log(str); //
//////////////////////////////
}// end switch case
///////////////////////////////
}); //ws end ws.onmessage
ws.on('error',function(e){console.log('ARI Connection error:',e);});
//////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
function get_uid(){
var rnd2 = Math.floor(MIN + Math.random()*(MAX + 1 - MIN));
//console.log("LEN ticket array: ",ticket_stasis.length);
let cnt = 0;
let i =45;
while(i){
ticket_stasis.forEach((element, index, array) => {
if(ticket_stasis[index].ch_b == rnd2){cnt = cnt + 1;}
//cnt = cnt + 1;
})
if(cnt == 0 ){rnd=rnd2; i=0;}
else{cnt=0;rnd2 = Math.floor(MIN + Math.random()*(MAX + 1 - MIN));}
}
//console.log("unicum == ",rnd );
rnd = rnd2;
return rnd2;
};
function continue_d(ch,cntxt,ep,pr,lbl){
var url;
url = 'http://' + ARI_HOST + ':' + ARI_PORT;
url = url + '/ari/channels/' + ch + '/continue?context=' + cntxt;
request.post( url,
{form: {
'extension': ep,
'priority':pr,
'label': lbl,
'api_key': API_KEY, }}
,function (error, response, body) {
if (!error) {
console.log( 'Create_continue Response Code:', response.statusCode );
console.log( 'Create_continue : ', ep );
}
}
)
}
function plus_bridge (brd){
//console.log('plus bridge');
request.post(
'http://' + ARI_HOST + ':' + ARI_PORT + '/ari/bridges/' + brd,
{
form: {
type: 'mixing',
name: brd,
'api_key': API_KEY,
}
},
function (error, response, body) {
if ( !error) {
// if ( !error && response.statusCode == 200) {
// console.log( 'stasis start. WS on message: ', b, ': ', response.statusCode );
console.log( 'Create Bridge Response code: ',':', response.statusCode );
console.log( 'Create Bridge: ', brd);
}
// moh_manage( data );
}
);
};
function minus_bridge (brd){
request.del(
'http://' + ARI_HOST + ':' + ARI_PORT + '/ari/bridges/' + brd,
{
form: {
'api_key': API_KEY,
},
},
function (error, response, body) {
if (!error) {
//if (!error && response.statusCode != 204) {
// console.log( ' WS on message: ', b, ': ', response.statusCode );
console.log('Delete Bridge Response code: ', response.statusCode);
console.log('Delete Bridge : ', brd);
}
}
);
// var url = 'http://' + ARI_HOST + ':' + ARI_PORT + '/ari/bridges/' + b + '?api_key=' + API_KEY;
};
function plus_ch_to_bridge (brd, ch){
//console.log('plus ch to bridge',brd,'channel ', ch);
request.post(
'http://' + ARI_HOST + ':' + ARI_PORT + '/ari/bridges/' + brd + '/addChannel?channel=' + ch,
{
form: {
// channel: ch,
'api_key': API_KEY,
}
},
function (error, response, body) {
if (!error && response.statusCode != 200) {
// console.log( 'stasis start. WS on message: ', b, ': ', response.statusCode );
console.log( 'Add channel to Bridge Response code: ', response.statusCode );
console.log( 'Add channel to Bridge: ', ch, 'To' , brd)
}
// moh_manage( data );
}
);
};
function minus_ch_from_bridge (brd, ch){
// var url = 'http://' + ARI_HOST + ':' + ARI_PORT + '/ari/bridges?bridgeId=' + BRIDGE_ID + '&api_key=' + API_KEY;
// http://192.168.88.25:8088/ari/bridges/1451451451/addChannel?channel=ХХХ_IN_ХХХХХ.ХХХ&api_key=ariuser:123
//http://192.168.88.25:8088/ari/bridges/1451451451/removeChannel?channel=1571734363.523&api_key=ariuser:123
request.del(
'http://' + ARI_HOST + ':' + ARI_PORT + '/ari/bridges/' + brd + '/removeChannel?channel=' + ch,
{
form: {
'api_key': API_KEY,
},
},
function (error, response, body) {
if (!error && response.statusCode != 204) {
// console.log( ' WS on message: ', b, ': ', response.statusCode );
console.log('Delete channel from Bridge Response code : ', response.statusCode);
console.log('Delete channel:', ch, ' from Bridge : ', brd);
}
}
);
// var url = 'http://' + ARI_HOST + ':' + ARI_PORT + '/ari/bridges/' + b + '/removeChannel?channel=' + ch + '&api_key=' + API_KEY;
};
вот index 'смотрелки' в базу
- Код: Выделить всё
<!doctype html>
<html>
<head>
<title>Start</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="keywords" content="">
<meta name="description" content="">
<meta name="msapplication-TileImage" content="img/logo.png">
<link rel="apple-touch-icon" sizes="192x192" href="img/logo.png">
<link rel="icon" type="image/png" sizes="192x192" href="img/logo.png">
<link rel="stylesheet" href="css/style.css" type="text/css">
</head>
<script type="text/javascript" src="js/jquery-3.4.1.js"></script>
<form method="post" enctype="application/x-www-form-urlencoded" action="index.php">
<br>
<fieldset class="field_set">
<legend class="title"> Перевод звонка на оператора </legend>
<table width="100%">
<tr>
<th> </th>
<th> </th>
<th> </th>
</tr>
<tr>
<td>
<label>
Номер клиента</label>
</td>
<td>
<input class="margin-left0" type="text" name="client" id="client" size="24">
<label>Перевод на </label>
<input class="margin-left0" type="text" name="oper" id="oper" size="10">
<?php
print '<input type="checkbox" name="oper" size="50" id="jbtn" value="oper" onchange="cl_btn()"> ';
print '<button id="form_submit" class="btn" value="" >';
print '<div id="txt_btn">Записать</div>';
print '</button>';
?>
</td>
</tr>
</table>
</fieldset>
<script type="text/javascript">
function cl_btn(){
var orig = '<div id="txt_btn">Записать</div>';
var w = '<label id="wr">Записать</label>';
var d = '<label id="dlt" >Удалить</label>';
var dd = '<div id="txt_btn">Удалить</div>';
if ($('#jbtn').is(':checked')){
$('#txt_btn').replaceWith(dd);
} else {
//$('#dlt').replaceWith(orig);
$('#txt_btn').replaceWith(orig);
}
}
</script>
<?php
include("./func/f_cdr.php");
isset($_POST['oper']);
//if($p){
$oper = $_POST["oper"];
$len_oper = strlen($oper);
$client =$_POST["client"];
$len_client = strlen($client);
if(isset($_POST['oper']) && $_POST['oper']== 'oper') {
//echo '+++++++++'.$p;
uregsqli("service_opers",$client,$oper,'1');
}else{
//if($len_oper==0 && $len_client){ }
uregsqli("service_opers",$client,$oper,'0');
}
/
?>
</form>
</html>
Нас определяет то, что мы делаем.