From: sleepy Date: Fri, 24 Apr 2020 13:54:54 +0000 (+1000) Subject: Добавлен новый функционал asyncAGI, исправлена ошибка в AGI Hangup X-Git-Url: http://git.ultra-x.su/?a=commitdiff_plain;h=53248955bc83750950c085d2e8eb7889e3235050;p=dev Добавлен новый функционал asyncAGI, исправлена ошибка в AGI Hangup --- diff --git a/astapilib/agi.php b/astapilib/agi.php index 426f031..98ecfbd 100644 --- a/astapilib/agi.php +++ b/astapilib/agi.php @@ -1,13 +1,9 @@ make_params(get_defined_vars()); $cmd = 'hangup'; $process_result = $this->ProcessCmd($cmd.$params); if ($process_result['code'] == 200) @@ -644,3 +641,17 @@ class AGI extends baseAGI return FALSE; } } + +class AGI +{ + use stdioAGI, baseAGI, funcAGI; +} + +class asyncAGI +{ + use callioAGI, baseAGI, funcAGI + { + callioAGI::__construct insteadof baseAGI; + baseAGI::__construct as subconstruct; + } +} \ No newline at end of file diff --git a/astapilib/ami.php b/astapilib/ami.php index 1e6ac1d..1795a9a 100644 --- a/astapilib/ami.php +++ b/astapilib/ami.php @@ -1,5 +1,5 @@ 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 } } - //Набор методов для работы со встроенной БД asterisk - public function AGI($Channel, $Command, $CommandID = NULL) + //отправка комманды 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 diff --git a/astapilib/baseagi.php b/astapilib/baseagi.php index ca0a369..da7fbc5 100644 --- a/astapilib/baseagi.php +++ b/astapilib/baseagi.php @@ -1,25 +1,103 @@ AmiInstance = &$AmiInstance; + $this->PutToBuffer($UriEncodedRequest); + $this->subconstruct(); + } + public function stop() + { + unset($this->AmiInstance); + $this->state = FALSE; + } + + public function PutToBuffer($uriencline) + { + $uriencline = str_replace('%FFFFFF', '%', $uriencline); + $lines = rawurldecode($uriencline); + $lines = explode("\n", $lines); + array_pop($lines); + foreach ($lines as $line) + { + $this->RxBuffer[] = $line; + } + } + + protected function RxData() + { + while (true) + { + $line = array_shift($this->RxBuffer); + if ($line === NULL) + { + usleep(250000); + } + else + { + return $line; + } + } + + } + + protected function TxData($cmd) + { + $this->AmiInstance->SendAsyncAGICmd($this->GetRequest('agi_channel'), $cmd); + return TRUE; + } +} + +trait baseAGI { protected $request = FALSE; protected $last_response = NULL; - + protected $state = FALSE; public function __construct() { + $this->request = $this->ProcessRequest(); if ($this->request === FALSE) { - return FALSE; + return; } + $this->state = TRUE; + } + + public function IsAlive() + { + return $this->state; } //получение запроса protected function ProcessRequest() { while(TRUE) { - $line = stream_get_line (STDIN , 1500, PHP_EOL); //получение сырых данных с парсингом по переводу строк + $line = $this->RxData(); if ($line === ''){break;} //пустая строка означает конец пакета if ($line === FALSE){return FALSE;} //false означает осутствие данных $parse_result = preg_match('/(^.[^ ]*): (.*)/', $line, $parsed_line); @@ -41,8 +119,13 @@ class baseAGI //обработка комманды protected function ProcessCmd($cmd) { - fwrite(STDOUT, $cmd.PHP_EOL); - $line = stream_get_line (STDIN , 1500, PHP_EOL); //получение сырых данных с парсингом по переводу строк + if (!$this->IsAlive()) + { + return FALSE; + } + + $this->TxData($cmd); + $line = $this->RxData(); $parse_result = preg_match('/(\d+)(?:.)(.*)/', $line, $parsed_line); if ($parse_result === 1) { diff --git a/astapilib/baseami.php b/astapilib/baseami.php index 28dae65..03d8727 100644 --- a/astapilib/baseami.php +++ b/astapilib/baseami.php @@ -1,5 +1,5 @@ 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 = []) { diff --git a/check_code.php b/check_code.php index 17b7393..de6edb3 100644 --- a/check_code.php +++ b/check_code.php @@ -1,12 +1,14 @@ \n"; -require_once 'astapilib/ami.php'; +echo "
\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