Страница 1 из 2

Вызов через БД

Добавлено: 09 апр 2020, 09:38
DmitryB
Добрый день, пока идут не запланированные каникулы решил заняться самообразование.
Иногда по работе приходится сталкиваться с Астериском. Решил освоить вызовы через Базу Данных (БД).
Для себя наметил задачу, поступает вызов на номер 101,далее в БД где происходит сравнение номеров в таблице, если нет соответствия вызов идет на номер 101, если соответствия есть вызов идет на номер из таблицы.
Как мне кажется я запутался с планом нумерации (dial plan) не правильно составил выражение и имеются проблемы

Код: Выделить всё

exten=> _101,1,Set(CALLERID(num)=${ODBC_forward_call(${CALLERID(num)})}) 
с БД а точнее с драйверами ODBC так же не все в порядке.
Таблица имеет вид:

Код: Выделить всё

mysql> SELECT * FROM forward_call;
+---------------------+------+-----+
| Date                | clid | dst |
+---------------------+------+-----+
| 2020-04-08 15:50:00 | 105  | 102 |
+---------------------+------+-----+
вывод логов:

Код: Выделить всё

[2020-04-09 09:37:57] WARNING[7232][C-0000004b]: func_odbc.c:476 execute: SQL Execute returned an error -1: 42S02: [MySQL][ODBC 5.3(w) Driver][mysqld-5.7.29-0ubuntu0.18.04.1]Table 'asterisktest.asterisktest' doesn't exist (106)
[2020-04-09 09:37:57] WARNING[7232][C-0000004b]: func_odbc.c:485 execute: SQL Exec Direct failed (-1)![SELECT dst FROM asterisktest where clid='102']
[2020-04-09 09:37:57] ERROR[7232][C-0000004b]: func_odbc.c:836 acf_odbc_read: Unable to execute query [SELECT dst FROM asterisktest where clid='102']
    -- Executing [101@Local:1] Set("SIP/102-00000069", "CALLERID(num)=") in new stack
    -- Auto fallthrough, channel 'SIP/102-00000069' status is 'UNKNOWN'
Заранее спасибо.

Re: Вызов через БД

Добавлено: 09 апр 2020, 11:43
ded
Рекомендации Создателей: вместо прямых odbc или mysql запросов вида [SELECT dst FROM asterisktest where clid='102']
из диалплана лучше написать небольшой скрипт на РНР например, протестировать его отдельно из командной строки, включив опции дебага, и, если всё ОК - вставить в диалплан через AGI, передаём в него параметр CID в качестве аргумента, получаем параметр Outbond CID в ответ:

Код: Выделить всё

exten=> _1ХХ,1,AGI(myscript,${EXTEN}) 
В директории /var/lib/asterisk/agi-bin полно примеров!

Table 'asterisktest.asterisktest' doesn't exist
Ну и коллегу zzuz буду цитировать постоянно:
Переводы с английского, дорого. ©

Re: Вызов через БД

Добавлено: 09 апр 2020, 12:07
DmitryB
Спасибо, срипты это следующий этап. Для меня сейчас стоит задача по работе с БД.

Re: Вызов через БД

Добавлено: 09 апр 2020, 13:21
Vlad1983
показываете таблицу forward_call, а спрашиваете asterisktest

Re: Вызов через БД

Добавлено: 09 апр 2020, 13:38
DmitryB
Спасибо большое. Поправил. но вызов до 102 не проходит через БД. Напрямую вызов проходит. лог при этом чист.

Re: Вызов через БД

Добавлено: 09 апр 2020, 14:38
ded
DmitryB писал(а):Спасибо, срипты это следующий этап. Для меня сейчас стоит задача по работе с БД.
Дмитрий, с базами данных как раз и надо работать через скрипты. Это удобней и правильней.
/var/lib/asterisk/agi-bin/sql.php -

Код: Выделить всё

<?php                                                                                                                                                     

/* $Id: sql.php 11662 2011-03-04 00:28:02Z p_lindheimer $ */                                                                                              

// SQL Abstraction Layer for AGI Applications                                                                                                             
// Original Release by Rob Thomas (xrobau@gmail.com)                                                                                                      
// Copyright Rob Thomas (2009) 
//  Commands:                                                                                                                                             
//                                                                                                                                                        
//  $AGI = new AGI();                                                                                                                                     
//  $db = new AGIDB($AGI);                                                                                                                                
//                                                                                                                                                        
//  $result = $db->escape($sql)                                                                                                                           
//      Escapes any characters that could confuse the database and lead to SQL injection problems.                                                        
//      You should use this on ANY browser-supplied or user-supplied input.                                                                               
//                                                                                                                                                        
//  $result = $db->sql($sql, $type)                                                                                                                       
//      Returns the result of the SQL command $sql.  This will die noisily if you                                                                         
//      try to do something that isn't portable between databases (eg ALTER TABLE                                                                         
//      or use CREATE with 'auto_increment') - use the alternate commands below,                                                                          
//      or design your database to be portable.                                                                                                           
//      $type specifies the return type -                                                                                                                 
//              ASSOC for an Associative array                                                                                                            
//              NUM for a numeric array.                                                                                                                  
//              BOTH for both in the same result                                                                                                          
//                                                                                                                                                        
//      Note this returns the ENTIRE result. So for example taken from routepermissions:                                                                  
//                                                                                                                                                        
//      $res = $db->sql("SELECT allowed,faildest FROM routepermissions WHERE exten='$cidnum' and routename='$routename'", "BOTH");                        
//                                                                                                                                                        
//      if allowed and faildest return 'NO' and 'ext-vm,300', the result would look like this:                                                            
//      $result = {                                                                                                                                       
//                      [0] =>  {                                                                                                                         
//                                      [0] = 'NO',             // Only these with 'NUM' type                                                             
//                                      [1] = 'ext-vm,300',                                                                                               
//                                      'allowed' => 'NO',      // Only these with 'ASSOC' type                                                           
//                                      'faildest => 'ext-vm,300',                                                                                        
//                              }                                                                                                                         
//                }                                                                                                                                       
//                                                                                                                                                        
//      if ($res[0]['allowed'] == 'NO') {                                                                                                                 
//              $agi->goto($res[0]['faildest']);                                                                                                          
//      }                                                                                                                                                 
//                                                                                                                                                        
//                                                                                                                                                        
//  $result = $db->rename_table($from, $to)                                                                                                               
//      Renames a table. Result is not null if an error occured, and the errorstr                                                                         
//      is in $result.                                                                                                                                    
//                                                                                                                                                        
//  $result = $db->add_col($tablename, $colname, $type)                                                                                                   
//      Add a column called $col_name of type $type to table $tablename. Result is not                                                                    
//      null if an error occured, and the errorstr is in $result.                                                                                         
//                                                                                                                                                        
//  $result = $db->drop_col($tablename, $colname)                                                                                                         
//      Drops a column from table $tablename. Actually drops the column if using MySQL,                                                                   
//      recreates the table if using SQLite.                                                                                                              
//                                                                                                                                                        
//  $result = $db->alter_col($tablename, $colname, $type)                                                                                                 
//      Changes the type of a column. Changes it directly in MySQL, recreates the table                                                                   
//      if using SQLite                                                                                                                                   
//                                                                                                                                                        

if (!class_exists('AGI')) {                                                                                                                               

}                                                                                                                                                         

class AGIDB {                                                                                                                                             
  // Database Variables from [globals]. Self explanatory.                                                                                                 
  private $dbhost;                                                                                                                                        
  private $dbuser;                                                                                                                                        
  private $dbpass;                                                                                                                                        
  private $dbfile;                                                                                                                                        
  private $dbname;                                                                                                                                        

  // sqlite3 needs some global variables to handle returns. They aren't needed                                                                            
  // to be defined here, but be aware that they are used by this module.                                                                                  

  /* global $sql3holderAssoc;   */                                                                                                                        
  /* global $sql3holderNum;     */                                                                                                                        
  /* global $sql3holderRowNbr;  */                                                                                                                        

  private $agi; // A copy of the AGI class already running                                                                                                
  private $db;  // 'mysql', 'sqlite' or 'sqlite3'. Set in sql_database_connect, so we                                                                     

  // Public things that you might need to access                                                                                                          

  public $errstr;       // Holder for error string                                                                                                        
  public $numrows;      // Number of rows returned in the query                                                                                           

  // Just in case someone REALLY wants to work around all the sanity checks here, these                                                                   
  // two variables are public, so you can use them if you REALLY must.                                                                                    
  public $dbtype;                                                                                                                                         
  public $dbhandle;                                                                                                                                       

  function AGIDB($AGI=null) {                                                                                                                             

  }                                                                                                                                                       

  function sql_database_connect() {                                                                                                                       

      // Determine DB type                                                                                                                              
      // dl() is gone in php5, but since this will crash it anyhow, will just leave it as is                                                              

  }                                                                                                                                                       
и так далее. Скрипт (выше) приведён не полностью.

Re: Вызов через БД

Добавлено: 09 апр 2020, 15:09
DmitryB
папка с скриптами у меня пустая, так что надо идти в гугл).
Объясните чем плох вариант работы с ODBC?
Вызовы пошли подмена происходит)) Еще раз спасибо.

Re: Вызов через БД

Добавлено: 09 апр 2020, 17:24
DmitryB
Vlad1983 писал(а):показываете таблицу forward_call, а спрашиваете asterisktest
Спасибо все отрабатывает корректно.
Дайте совет каким образом можно направить вызов на номер если номер вызывающего абонента отсутствует в таблице.

Re: Вызов через БД

Добавлено: 12 апр 2020, 21:45
DmitryB
Вызов через БД проходит все хорошо, но нуждаюсь в помощи.
При вызове с номера который присутствует в БД вызов идет на номер абонента 102. У абонента 102 происходит вызов, но отображение как будто абонент 102 набирает номер.

Код: Выделить всё

     > 0x7fbf8c03b430 -- Strict RTP learning after remote address set to: 10.0.0.9:4074
    -- Executing [104@Local:1] Set("SIP/105-000000a9", "BNUM=104") in new stack
    -- Executing [104@Local:2] Set("SIP/105-000000a9", "CALLERID(num)=102") in new stack
    -- Executing [104@Local:3] Dial("SIP/105-000000a9", "SIP/102,60") in new stack
  == Using SIP RTP CoS mark 5
 exten => 104,1,Set(BNUM=${CALLERID(DNID)}); забираем данные о Б номере и кладем их в переменную BNUM
    same => n,Set(CALLERID(num)=${IF($["${ODBC_forward_call(${CALLERID(num)})}" = "" ]?${BNUM}:${ODBC_forward_call(${CALLERID(num)})})})
;Номер А входящего вызова сравниваем с БД и если номер совпадает, отправляем его на номер из БД, если номер не совпадает то отправляем его на номер переменной BNUM

Код: Выделить всё

    same => n,Dial(SIP/${CALLERID(num)},60); Делаем вызов на номер заимвствованный из БД

Re: Вызов через БД

Добавлено: 12 апр 2020, 22:41
zzuz
Set("SIP/105-000000a9", "CALLERID(num)=102")

научитесь уже читать логи.