Exemple #1
0
 /**
  * Handle an FCGI STDIN record that transfers request body data.
  * 
  * @param Record $record
  * @param Channel $incoming
  */
 public function handleStdin(Record $record, Channel $incoming) : \Generator
 {
     if (!$this->received) {
         $this->received = true;
         $request = $this->buildRequest();
         $incoming->send([$this, $request]);
     }
     if ($record->data === '') {
         return $this->body->close();
     }
     return (yield $this->body->send($record->data));
 }
Exemple #2
0
 /**
  * Coroutine that handles incoming WebSocket frames.
  */
 protected function processIncomingFrames() : \Generator
 {
     $e = null;
     try {
         while (true) {
             $frame = (yield from $this->readNextFrame());
             if ($frame->isControlFrame()) {
                 if (!(yield from $this->handleControlFrame($frame))) {
                     break;
                 }
             } else {
                 switch ($frame->opcode) {
                     case Frame::TEXT:
                         yield from $this->handleTextFrame($frame);
                         break;
                     case Frame::BINARY:
                         yield from $this->handleBinaryFrame($frame);
                         break;
                     case Frame::CONTINUATION:
                         yield from $this->handleContinuationFrame($frame);
                         break;
                 }
             }
         }
     } catch (\Throwable $e) {
         $this->messages->close($e);
     } finally {
         $this->messages->close();
         try {
             foreach ($this->pings as $defer) {
                 $defer->fail($e ?? new \RuntimeException('WebSocket connection closed'));
             }
         } finally {
             $this->pings = [];
         }
         try {
             if ($this->socket->isAlive()) {
                 $reason = $e === null || $e->getCode() === 0 ? Frame::NORMAL_CLOSURE : $e->getCode();
                 (yield $this->writer->sendFrame(new Frame(Frame::CONNECTION_CLOSE, \pack('n', $reason))));
             }
         } finally {
             if ($this->logger) {
                 $this->logger->debug('WebSocket connection to {peer} closed', ['peer' => $this->socket->getRemoteAddress()]);
             }
             $this->socket->close();
         }
     }
 }
Exemple #3
0
 protected function wireMapper(callable $map, Channel $input, int $concurrency = 1) : Channel
 {
     $output = new Channel($concurrency * 2);
     $executor = new Executor($concurrency);
     $closed = false;
     $count = 0;
     $n = 0;
     $job = null;
     $job = function () use(&$job, &$count, &$n, &$closed, $executor, $map, $input, $output) {
         try {
             if ($this->eof === ($val = (yield $input->receive($this->eof)))) {
                 if (--$count < 1) {
                     $output->close();
                 }
                 return;
             }
             $val = $map($val, $n++);
             if ($val instanceof \Generator) {
                 $val = (yield from $val);
             }
             if (!$closed) {
                 (yield $output->send($val));
                 $executor->execute($job);
             }
         } catch (\Throwable $e) {
             if (!$closed) {
                 $closed = true;
                 $output->close($e);
             }
         }
     };
     for ($i = 0; $i < $concurrency; $i++) {
         $count++;
         $executor->execute($job);
     }
     return $output;
 }
Exemple #4
0
 protected function socketWriter($socket, Channel $channel, callable $transform = null) : \Generator
 {
     $writer = new SocketWriter($socket);
     $len = 0;
     try {
         while (null !== ($chunk = (yield $channel->receive()))) {
             $len += (yield $writer->write($transform ? $transform($chunk) : $chunk));
         }
         return $len;
     } catch (\Throwable $e) {
         $channel->close($e);
         throw $e;
     } finally {
         $writer->dispose();
     }
 }
Exemple #5
0
 /**
  * Coroutine that parses incoming requests and queues them into the request pipeline.
  * 
  * @param DuplexStream $socket Stream being used to transmit HTTP messages.
  * @param Channel $pipeline HTTP request pipeline.
  * @param HttpRequest $request First HTTP request within the pipeline.
  */
 protected function parseIncomingRequests(HttpDriverContext $context, SocketStream $socket, Channel $pipeline, HttpRequest $request) : \Generator
 {
     try {
         do {
             $request = $request ?? (yield from $this->parseNextRequest($context, $socket));
             $close = $this->shouldConnectionBeClosed($request);
             (yield $pipeline->send([$request, $close]));
             (yield ((yield $request->getBody()->getReadableStream()))->getAwaitable());
             $request = null;
         } while (!$close);
         $pipeline->close();
     } catch (\Throwable $e) {
         $pipeline->close($e);
     }
 }
Exemple #6
0
 /**
  * Closes the event source.
  */
 public function close()
 {
     $this->channel->close();
 }