2015-12-07 143 views
2

我想讀取一個長時間運行的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

回答

0

你可以使用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