阅读长时间运行的PHP进程客户端端

问题描述:

我想读取一个长时间运行的php进程,当满足条件时会返回数据。阅读长时间运行的PHP进程客户端端

从我的研究,我碰到:

  • 长轮询
  • 插座(socket.io &的node.js)
  • 棘轮

我努力理解&应用我的问题的实施。我在PHP下面的循环:

public function store(ClientImpl $a) 
{ 
    $request = \Illuminate\Support\Facades\Request::all(); 
    $originateMsg = new OriginateAction('Local/' . $request['agent'] . '@auto-answer'); 
    $originateMsg->setContext('G-Outgoing'); 
    $originateMsg->setPriority('1'); 
    $originateMsg->setExtension($request['dial']); 
    $a->send($originateMsg); 

    while(true) { 
     if($a->process()) break; 
     usleep(1000); 
    } 

    $a->close(); 

    echo 'OK'; 
    ob_end_flush(); 
    flush(); 
} 

$a->process()调用下面的方法:

/** 
* Main processing loop. Also called from send(), you should call this in 
* your own application in order to continue reading events and responses 
* from ami. 
*/ 
public function process() 
{ 
    $msgs = $this->getMessages(); 
    foreach ($msgs as $aMsg) { 
     if ($this->_logger->isDebugEnabled()) { 
      $this->_logger->debug(
       '------ Received: ------ ' . "\n" . $aMsg . "\n\n" 
      ); 
     } 
     $resPos = strpos($aMsg, 'Response:'); 
     $evePos = strpos($aMsg, 'Event:'); 
     if (($resPos !== false) && (($resPos < $evePos) || $evePos === false)) { 
      $response = $this->_messageToResponse($aMsg); 
      $this->_incomingQueue[$response->getActionId()] = $response; 
     } else if ($evePos !== false) { 
      $event = $this->_messageToEvent($aMsg); 
      $response = $this->findResponse($event); 
      if ($response === false || $response->isComplete()) { 
       $this->dispatch($event); 
      } else { 
       $response->addEvent($event); 
      } 
     } else { 
      // broken ami.. sending a response with events without 
      // Event and ActionId 
      $bMsg = 'Event: ResponseEvent' . "\r\n"; 
      $bMsg .= 'ActionId: ' . $this->_lastActionId . "\r\n" . $aMsg; 
      $event = $this->_messageToEvent($bMsg); 
      $response = $this->findResponse($event); 
      $response->addEvent($event); 
     } 
     if ($this->_logger->isDebugEnabled()) { 
      $this->_logger->debug('----------------'); 
     } 
    } 
} 

$a->process()然后叠出事件消息,阅读这些,我创建的IEventListener实现其也被称为“背后场景'当$a->process()被调用。

class VoipEventStart implements IEventListener 
{ 
    public function handle(EventMessage $event) 
    { 
     $a = $event->getKeys(); 

     if(($a['event'] == "Hangup" || $a['event'] == "HangupRequest") && strpos($a['channel'], 'SIP/') !== FALSE) 
     { 
      return true; 
     } 

     return false; 
    } 
} 

处理方法在用户处于活动呼叫时从Asterisk PBX系统读取事件。这意味着只要通话持续,处理循环就会持续。

如何在没有浏览器看起来像加载/等待的情况下执行此客户端?

+0

你的意思是简单的ajax? – Naruto

+0

$ a-> process()是做什么的?它运行多久?它返回什么? – marekful

+0

我没有看到process()返回任何东西。但是当你的例子中的循环会在process()返回truthy时断开/停止。 – marekful

你可以使用Server Sent Events或一些套接字的实现,但最简单的可能是一个长期轮询策略会工作得很好。

为此,从客户端发送一个普通的AJAX请求,并使服务器仅在符合条件时才返回。这可能是因为改变了服务器端代码如下简单:

while(true) { 
    if($a->process()) break; 
    usleep(1000); 
} 
echo 'OK'; 
ob_end_flush(); 
flush(); 

而且客户端应该发送一个简单的GET请求启动上述循环的PHP文件。这种方式当一个响应返回到这个请求时,你知道process()返回true。

客户端代码可能看起来是这样的:

<div>Call status: <span id="status">In call</span></div> 
<script> 
    $.get('/check_call_status.php?callerId=123', function(response) { 
    if(response === 'OK') { 
     $('#staus').html('finished'); 
    } 
    }); 
</script> 

当然,这可能是更复杂的处理超时。例如。如果在给定时间段内没有对长轮询请求做出响应,请重新启动它 - 即中止请求并再次发送,以避免客户端或服务器超时。

+0

我试过这个&超时似乎是大问题。如果调用持续时间超过超时时间,则Ajax调用失败。我不能重新请求这个,因为它取决于$ a的具体实现(请参阅更新的'store'方法。)意思是每次我重新请求时,我都会得到一个新的实现。你会建议什么? – jakehallas

+0

比它听起来像一个设计缺陷。呼叫者或现有呼叫必须有某种标识符。使用它,应该可以返回到事件状态检查器循环。如果调用不再存在(例如调用$ a-> close()),您应该能够检测到并立即返回。 – marekful

+0

中止AJAX请求将执行其'anobort'回调,因此它不应该用虚假信息更新客户端。在发生任何超时之前使用长轮询中止请求并立即重新启动它是一种很好的做法。 – marekful