Exemple #1
0
 /**
  * Send an event to the client.
  * 
  * @param string $message The message payload to be sent.
  * @param string $event Type of the event.
  * 
  * @throws \InvalidArgumentException When the given message is not a valid UTF-8 string.
  */
 public function send(string $message, string $event = null) : Awaitable
 {
     if (!\preg_match('//u', $message)) {
         throw new \InvalidArgumentException('SSE messages must be encoded as UTF-8 strings');
     }
     $data = \str_replace("\n", "\ndata: ", $message);
     if ($event === null) {
         $event = '';
     } else {
         $event = "event: {$event}\n";
     }
     return $this->channel->send($event . "data: {$data}\n\n");
 }
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();
         }
     }
 }
 /**
  * {@inheritdoc}
  */
 public function channel(int $chunkSize = 4096, int $length = null) : Channel
 {
     return Channel::fromGenerator(16, function (Channel $channel) use($chunkSize, $length) {
         (yield $this->executor->execute(function () use($channel, $chunkSize, $length) {
             $remaining = $length ?? \PHP_INT_MAX;
             while ($remaining && null !== ($chunk = (yield $this->stream->readBuffer(\min($remaining, $chunkSize))))) {
                 $remaining -= \strlen($chunk);
                 (yield $channel->send($chunk));
             }
         }));
     });
 }
Exemple #4
0
 protected function doReduce($reduced, callable $reduce, Channel $input, bool $withCount = false) : \Generator
 {
     $n = 0;
     while ($this->eof !== ($val = (yield $input->receive($this->eof)))) {
         $reduced = $reduce($reduced, $val, $n++);
     }
     return $withCount ? [$reduced, $n] : $reduced;
 }
Exemple #5
0
 /**
  * {@inheritdoc}
  */
 public function channel(int $chunkSize = 4096, int $length = null) : Channel
 {
     $size = (int) \max(1, \ceil($this->readBufferSize / $chunkSize));
     return Channel::fromGenerator($size, function (Channel $channel) use($chunkSize, $length) {
         $remaining = $length ?? \PHP_INT_MAX;
         while ($remaining && null !== ($chunk = (yield $this->readBuffer(\min($remaining, $chunkSize))))) {
             $remaining -= \strlen($chunk);
             (yield $channel->send($chunk));
         }
     });
 }
Exemple #6
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 #7
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 #8
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 #9
0
 /**
  * Read the next inbound HTTP request.
  */
 public function nextRequest() : Awaitable
 {
     return $this->incoming->receive();
 }
 /**
  * {@inheritdoc}
  */
 public function channel(int $chunkSize = 4096, int $length = null) : Channel
 {
     $chunk = \substr($this->buffer, $this->offset, $length ?? \PHP_INT_MAX);
     $this->offset += \strlen($chunk);
     return Channel::fromArray(\str_split($chunk, $chunkSize));
 }