]> Untitled Git - dev/commitdiff
Добавлен новый функционал asyncAGI, исправлена ошибка в AGI Hangup
authorsleepy <sleepy@vvsu.ru>
Fri, 24 Apr 2020 13:54:54 +0000 (23:54 +1000)
committersleepy <sleepy@vvsu.ru>
Fri, 24 Apr 2020 13:54:54 +0000 (23:54 +1000)
astapilib/agi.php
astapilib/ami.php
astapilib/baseagi.php
astapilib/baseami.php
check_code.php

index 426f031443a30698e91af0ba386578c038d208fd..98ecfbd4ecaae4904ef84a467ea6c4a3f61488ba 100644 (file)
@@ -1,13 +1,9 @@
 <?php\r
-//V1.0\r
+//V1.1\r
 require_once(__DIR__.DIRECTORY_SEPARATOR.'baseagi.php');\r
 \r
-class AGI extends baseAGI\r
+trait funcAGI\r
 {\r
-    public function __construct()\r
-    {\r
-       parent::__construct();\r
-    }\r
     \r
     //подготовка параметров для передачи\r
     protected function make_params($inparams)\r
@@ -55,6 +51,7 @@ class AGI extends baseAGI
     //Hangup a channel.\r
     public function Hangup($channelname = NULL)\r
     {\r
+       $params = $this->make_params(get_defined_vars());\r
        $cmd = 'hangup';\r
        $process_result = $this->ProcessCmd($cmd.$params);\r
        if ($process_result['code'] == 200)\r
@@ -644,3 +641,17 @@ class AGI extends baseAGI
        return FALSE;   \r
     }        \r
 }\r
+\r
+class AGI \r
+{\r
+   use stdioAGI, baseAGI, funcAGI;\r
+}\r
+\r
+class asyncAGI \r
+{\r
+    use callioAGI, baseAGI, funcAGI\r
+    {\r
+       callioAGI::__construct insteadof baseAGI;\r
+       baseAGI::__construct as subconstruct;\r
+    }\r
+}
\ No newline at end of file
index 1e6ac1dffdbd08caf03f0f1cae7a5b002a5b29b7..1795a9a5b66f9e4cce87b665703bc6c55987a685 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-//V1.0
+//V1.1
 /*
 
 
@@ -8,12 +8,16 @@
 require_once(__DIR__.DIRECTORY_SEPARATOR.'common.php');
 require_once(__DIR__.DIRECTORY_SEPARATOR.'baseami.php');
 require_once(__DIR__.DIRECTORY_SEPARATOR.'timer.php');
+require_once(__DIR__.DIRECTORY_SEPARATOR.'agi.php');
+
 
 class AMI extends baseAMI
 {
     protected $semaphores = [];
     protected $TMP = [];
-     
+    protected $AGIs = []; 
+
+
     //конструктор установка параметров
     public function __construct($config = [])
     {
@@ -29,6 +33,9 @@ class AMI extends baseAMI
            }
                
        }
+       $this->add_event_handler('AsyncAGIStart', [$this, 'AsyncAGIStartHdl']);
+       $this->add_event_handler('AsyncAGIEnd', [$this, 'AsyncAGIEndHdl']);
+       $this->add_event_handler('AsyncAGIExec', [$this, 'AsyncAGIExecHdl']);
     }
     
     //генерирует MD5 challenge для аутентификации (не понятно где применять)
@@ -135,8 +142,8 @@ class AMI extends baseAMI
        }
     }
     
-    //Ð\9dабоÑ\80 Ð¼ÐµÑ\82одов Ð´Ð»Ñ\8f Ñ\80абоÑ\82Ñ\8b Ñ\81о Ð²Ñ\81Ñ\82Ñ\80оенной Ð\91Ð\94 asterisk
-    public function AGI($Channel, $Command, $CommandID = NULL)
+    //оÑ\82пÑ\80авка ÐºÐ¾Ð¼Ð¼Ð°Ð½Ð´Ñ\8b asyncAGI
+    public function SendAsyncAGICmd($Channel, $Command, $CommandID = NULL)
     {  
        $params = $this->make_params(get_defined_vars());
        $ActId = $this->send_action('AGI', $params);
@@ -144,6 +151,8 @@ class AMI extends baseAMI
        LOG::log(__METHOD__.' '.$response['Message'], 5);
        if ($response['Response'] == 'Success')
        {
+           //$this->SetEventHook($ActionID, $Callback);
+           
            return TRUE;
        }
        else
@@ -408,7 +417,9 @@ class AMI extends baseAMI
        LOG::log(__METHOD__.' '.$response['Message'], 5);
        if ($response['Response'] == 'Success')
        {
-           return $response['ActionID'];
+           $retevent = new AMIEvent();
+           $this->SetEventHook($response['ActionID'], [$retevent, 'SetData']);
+           return $retevent;
        }
        else
        {
@@ -1997,4 +2008,74 @@ class AMI extends baseAMI
        }
        return $retval;
     }
+    
+    //обработчик запуска asyncagi
+    protected function AsyncAGIStartHdl($event_name, $event)
+    {
+       $this->AGIs[$event['Channel']] = new asyncAGI($event['Env'], $this);
+    }
+    
+    //обработчик завершения asyncagi
+    protected function AsyncAGIEndHdl($event_name, $event)
+    {
+       $this->AGIs[$event['Channel']]->stop();
+       unset($this->AGIs[$event['Channel']]);
+    }
+    
+    //обработчик входного буфера asyncAGI
+    public function AsyncAGIExecHdl($event_name, $event)
+    {
+       $this->AGIs[$event['Channel']]->PutToBuffer($event['Result']);
+    }
+    
+    
+    //получить instance asyncAGI
+    public function GetAsyncAGIInstance($channel)
+    {
+       if (isset($this->AGIs[$channel]))
+       {
+           return $this->AGIs[$channel];
+       }
+       else
+       {
+           return FALSE;
+       }
+    }
+    
+    //получить список каналов с запущенными AsyncAGI
+    public function GetAsyncAGIChannelList()
+    {
+       return array_keys($this->AGIs);
+    }
+    
+}
+
+class AMIEvent 
+{
+    private $state = FALSE;
+
+    public function SetData($data)
+    {
+       if (!$this->state)
+       {
+           foreach ($data as $var => $value)
+           {
+               $this->$var = $value;           
+           }
+           $this->state = TRUE;
+       }
+    }
+       
+    public function IsReady()
+    {
+       return $this->state;
+    }
+    
+    public function WaitUntilReady()
+    {
+       while (!$this->state)
+       {
+           usleep(100000);
+       }
+    }
 }
\ No newline at end of file
index ca0a369ea640a47eb1b3bf3380bdb8785fec2159..da7fbc51236372c1b5174b7afaae65bcea5276b6 100644 (file)
 <?php\r
-//V1.0\r
-class baseAGI\r
+//V1.1\r
+trait stdioAGI\r
+{\r
+\r
+    protected function RxData()\r
+    {\r
+       $line = stream_get_line (STDIN , 1500, PHP_EOL); //получение сырых данных с парсингом по переводу строк\r
+       return $line;\r
+\r
+    }\r
+\r
+    protected function TxData($cmd)\r
+    {\r
+       fwrite(STDOUT, $cmd.PHP_EOL);\r
+    }\r
+\r
+\r
+}\r
+\r
+trait callioAGI\r
+{\r
+    protected $RxBuffer = [];\r
+    protected $AmiInstance;\r
+    \r
+    public function __construct($UriEncodedRequest,$AmiInstance)\r
+    {\r
+       $this->AmiInstance = &$AmiInstance;\r
+       $this->PutToBuffer($UriEncodedRequest);\r
+       $this->subconstruct();\r
+    }\r
+    public function stop()\r
+    {\r
+       unset($this->AmiInstance);\r
+       $this->state = FALSE;\r
+    }\r
+\r
+    public function PutToBuffer($uriencline)\r
+    {\r
+       $uriencline = str_replace('%FFFFFF', '%', $uriencline);\r
+       $lines = rawurldecode($uriencline);\r
+       $lines = explode("\n", $lines); \r
+       array_pop($lines);\r
+       foreach ($lines as $line)\r
+       {\r
+           $this->RxBuffer[] = $line;\r
+       }\r
+    }\r
+    \r
+    protected function RxData()\r
+    {\r
+       while (true)\r
+       {\r
+           $line = array_shift($this->RxBuffer);\r
+           if ($line === NULL)\r
+           {\r
+               usleep(250000);\r
+           }\r
+           else\r
+           {\r
+               return $line;\r
+           }\r
+       }\r
+\r
+    }\r
+\r
+    protected function TxData($cmd)\r
+    {\r
+       $this->AmiInstance->SendAsyncAGICmd($this->GetRequest('agi_channel'), $cmd);\r
+       return TRUE;\r
+    }\r
+}\r
+\r
+trait baseAGI\r
 {\r
     protected $request = FALSE;\r
     protected $last_response = NULL;\r
-\r
+    protected $state = FALSE;\r
 \r
     public function __construct()\r
     {\r
+       \r
        $this->request = $this->ProcessRequest();\r
        if ($this->request === FALSE)\r
        {\r
-           return FALSE;\r
+           return;\r
        }\r
+       $this->state = TRUE;\r
+    }\r
+    \r
+    public function IsAlive()\r
+    {\r
+       return $this->state;\r
     }\r
     //получение запроса\r
     protected function ProcessRequest()\r
     {\r
        while(TRUE)\r
        {\r
-           $line = stream_get_line (STDIN , 1500, PHP_EOL); //получение сырых данных с парсингом по переводу строк\r
+           $line = $this->RxData();\r
            if ($line === ''){break;} //пустая строка означает конец пакета\r
            if ($line === FALSE){return FALSE;} //false означает осутствие данных\r
            $parse_result = preg_match('/(^.[^ ]*): (.*)/', $line, $parsed_line);\r
@@ -41,8 +119,13 @@ class baseAGI
     //обработка комманды\r
     protected function ProcessCmd($cmd)\r
     {\r
-       fwrite(STDOUT, $cmd.PHP_EOL);\r
-       $line = stream_get_line (STDIN , 1500, PHP_EOL); //получение сырых данных с парсингом по переводу строк\r
+       if (!$this->IsAlive())\r
+       {\r
+           return FALSE;\r
+       }\r
+\r
+       $this->TxData($cmd);\r
+       $line = $this->RxData();\r
        $parse_result = preg_match('/(\d+)(?:.)(.*)/', $line, $parsed_line);\r
        if ($parse_result === 1)\r
        {\r
index 28dae65c2693ff7c2291827758b9545a4d763324..03d8727506a71f218a93a37808f8290f57941429 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-//V1.0
+//V1.1.0
 class baseAMI
 {
     protected $conn_handle = FALSE;
@@ -7,6 +7,7 @@ class baseAMI
     protected $events = [];
     protected $responses = [];
     protected $event_handlers = [];
+    protected $event_hooks = [];
     protected $refresh_lock = FALSE;
     
     //конструктор, настройка по умолчанию 
@@ -220,8 +221,19 @@ class baseAMI
     {
        foreach ($this->events as $index => $event)
        {
-           
            $event_name = strtolower($event['Event']);
+           if (isset($event['ActionID']))
+           {
+               if (isset($this->event_hooks[$event['ActionID']]))
+               {
+                   if (is_callable($this->event_hooks[$event['ActionID']]))
+                   {
+                       LOG::log("Hooked event '${event_name}' with ActionID '{$event['ActionID']}'.",5);
+                       call_user_func($this->event_hooks[$event['ActionID']], $event);
+                       unset($this->event_hooks[$event['ActionID']]);
+                   }
+               }
+           }
            if (isset($this->event_handlers[$event_name]))
            {
                $run_handler = $this->event_handlers[$event_name];
@@ -249,12 +261,27 @@ class baseAMI
            else
            {
                LOG::log("Got event '${event_name}', runing '${run_handler_name}' handler for processing it.",5);
-               $ret_h_data = call_user_func($run_handler, $event_name, $event);
+               call_user_func($run_handler, $event_name, $event);
            }
            unset($this->events[$index]);
        }
     }
 
+    //установить hook на событие по ActionID
+    public function SetEventHook($ActionID, $Callback)
+    {
+       if (is_callable($Callback))
+       {
+           $this->event_hooks[$ActionID] = $Callback;
+       }
+    }
+    
+    //снять hook на событие по ActionID
+    public function UnsetEventHook($ActionID)
+    {
+       unset($this->event_hooks[$ActionID]);
+    }
+    
     //низкоуровневая отправка запросов
     protected function send_action($action,$params = [])
     {  
index 17b73930f9054536a760a7c10cb9de4e7e16edf1..de6edb38b5b76eb6df51a1a9de2fe8a9ea51f837 100644 (file)
@@ -1,12 +1,14 @@
 <?php
+declare (ticks=1);
+require_once 'astapilib/ami.php';
 function waitanswer($a,$b)
 {
     var_dump($a,$b);
-    var_dump(get_defined_vars());
+    var_dump(urldecode($b['Result']));
 }
-echo "<pre>\n";
-require_once 'astapilib/ami.php';
 
+echo "<pre>\n";
+$_GET['phone'] = 3400;
 var_dump($_GET);
 if (!isset($_GET['phone']))
 {
@@ -19,15 +21,29 @@ if(preg_match('/^7\d{10}$/', $_GET['phone']) != 1)
 
 $AMI = new AMI(array('autorefresh' => TRUE, 'logverbose' => 6));
 $is_connected = $AMI->connect("127.0.0.1", "monast", "blabla");
-$AMI->add_event_handler('originateresponse', 'waitanswer');
-$AMI->enable_events(TRUE);
 
 if (!$is_connected)
 {
     exit();
 }
 
-var_dump($AMI->Originate("Local/{$_GET['phone']}@c-2", NULL, NULL, NULL, 'AGI', 'agi:async', 30, 3500, NULL, NULL, NULL, NULL, 'azaza', 'ololo'));
+$OriginateResponce = $AMI->Originate("Local/{$_GET['phone']}@c-2", NULL, NULL, NULL, 'AGI', 'agi:async', 30, 3500, NULL, NULL, NULL, NULL);
+$OriginateResponce->WaitUntilReady();
+$channel = $OriginateResponce->Channel;
+var_dump($AMI->GetAsyncAGIChannelList());
+$AGI = $AMI->GetAsyncAGIInstance($channel);
+//$AGI = new AGI();
+echo '------------------';
+var_dump($AGI->GetVariable('CALLERID(num)'));
+var_dump($AGI->GetVariable('CALLERID(name)'));
 
+echo '------------------';
+var_dump($AGI->SayDigits('012345'));
+var_dump($AGI->Hangup());
+unset($AGI);
 sleep(5);
-$AMI->AGI("Local/{$_GET['phone']}@c-2", 'NoOp');
\ No newline at end of file
+while (TRUE)
+{
+    sleep(1);
+    echo '+';
+}
\ No newline at end of file