简体   繁体   English

阅读长期运行的PHP流程客户端

[英]Read long-running PHP process client side

I want to read a long-running php process that will return data when a criterion is met. 我想阅读一个长期运行的php流程,该流程将在满足条件时返回数据。

From my research, I have came across: 从我的研究中,我发现:

  • Long polling 长时间轮询
  • Sockets (socket.io & node.js) 套接字(socket.io和node.js)
  • Ratchet 棘轮

I am struggling to understand & apply an implementation of my problem. 我正在努力理解并应用我的问题的实现。 I have the following loop in PHP: 我在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() calls the following method: $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() then stacks up Event messages, to read these I create an implementation of IEventListener which is also called 'behind the scenes' when $a->process() is called. 然后$a->process()堆叠事件消息,以读取这些消息,我创建了IEventListener的实现, 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;
    }
}

The process method reads events from an Asterisk PBX system while a user is on an active call. 当用户正在进行通话时,该处理方法会从Asterisk PBX系统读取事件。 This means the process loop will last as long as the call lasts. 这意味着过程循环将一直持续到调用持续。

How would I execute this client-side without the browser looking like it is loading/waiting? 在浏览器看起来没有加载/等待状态的情况下,如何执行此客户端?

You could use Server Sent Events or some socket implementation but for simplest probably a long-poll strategy would work out well enough. 您可以使用“ 服务器发送事件”或某些套接字实现,但是对于最简单的方法来说,长轮询策略可能效果很好。

For that, send a plain AJAX request from the client and make server only return when the criterion is met. 为此,请从客户端发送普通的AJAX请求,并使服务器仅在满足条件时才返回。 It could be as simple as changing the server side code as follows: 它可以像更改服务器端代码一样简单,如下所示:

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

And the client should send a simple GET request to the PHP file that starts the above loop. 并且客户端应该向启动上述循环的PHP文件发送一个简单的GET请求。 This way when a response comes back to this request, you know process() return true. 这样,当响应返回到该请求时,您知道process()返回true。

The client code could look something like this: 客户端代码可能如下所示:

<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>

Of course, this could be more sophisticated to deal with timeouts. 当然,处理超时可能更复杂。 Eg if there's no response to the long-poll request for a given time period, restart it - ie abort the request and send it again to avoid client or server timeouts. 例如,如果在给定的时间段内对长轮询请求无响应,请重新启动它-即中止该请求并再次发送以避免客户端或服务器超时。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM