Example #1
0
 /**
  * @recoil-coroutine
  */
 private function connectSocket(ConnectionOptions $options) : Generator
 {
     $errorCode = null;
     $errorMessage = null;
     $stream = @stream_socket_client(\sprintf('tcp://%s:%s', $options->host(), $options->port()), $errorCode, $errorMessage, 0, STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT);
     if ($stream === false) {
         throw SingleConnectionException::couldNotConnect($options, $errorCode . ': ' . $errorMessage);
     }
     // Wait for the socket to open or fail ...
     stream_set_blocking($stream, false);
     list(, $writable) = (yield Recoil::select([$stream], [$stream]));
     if (empty($writable)) {
         throw SingleConnectionException::couldNotConnect($options, 'connection refused');
     }
     return $stream;
 }
Example #2
0
 /**
  * Set the pre-fetch limits for this connection.
  *
  * @recoil-coroutine
  *
  * The pre-fetch count is the maximum number of unacknowledged messages that
  * are delivered to this connection.
  *
  * The pre-fetch limit is the maximum total size of unacknowledge messages
  * (in bytes) that is delivered to this connection.
  *
  * This feature is incompatible with the "per_consumer_qos" broker
  * capability.
  *
  * RabbitMQ does not support per-connection limits (current as of v3.5.6).
  *
  * @param int|null     $count   The pre-fetch count limit (null = unlimited).
  * @param int|null     $size    The pre-fetch size limit (null = unlimited).
  * @param Channel|null $channel The application-managed channel to use (null = auto-managed).
  *
  * @throws NotSupportedException The broker does not support this feature.
  * @throws ConnectionException   The connection is closed.
  */
 public function setQosLimits(int $count = null, int $size = null, Channel $channel = null) : Generator
 {
     assert($size === null || $size > 0);
     assert($count === null || $count > 0);
     if ($this->connectionManager === null) {
         throw SingleConnectionException::notOpen($this->options);
     } elseif ($this->features->perConsumerQos) {
         throw NotSupportedException::incompatibleCapability('per-connection QoS limits', 'per_consumer_qos');
     } elseif ($size !== null && !$this->features->qosSizeLimits) {
         throw NotSupportedException::unsupportedFeature('pre-fetch size limits');
     }
     $channelManager = (yield $this->connectionManager->acquireChannel($channel));
     try {
         (yield $channelManager->call(BasicQosFrame::create($size ?: 0, $count ?: 0, true), BasicQosOkFrame::METHOD_ID));
     } finally {
         if ($channel === null) {
             $channelManager->release();
         }
     }
 }
Example #3
0
 private function readLoop() : Generator
 {
     try {
         while ($this->state === ConnectionState::OPEN) {
             $frame = (yield $this->transport->read());
             $this->heartbeatsSinceFrameReceived = 0;
             if ($frame instanceof HeartbeatFrame) {
                 continue;
             } elseif ($frame->frameChannelId > 0) {
                 $channelManager = $this->channels[$frame->frameChannelId] ?? null;
                 if ($channelManager === null) {
                     throw ProtocolException::unexpectedFrame($frame, \sprintf('channel #%s is closed', $frame->frameChannelId));
                 }
                 (yield $channelManager->dispatch($frame));
             } elseif ($frame instanceof ConnectionCloseFrame) {
                 (yield $this->transport->close());
                 throw AmqpException::create($frame->replyText, $frame->replyCode);
             } else {
                 throw ProtocolException::unexpectedFrame($frame, 'received on channel #0');
             }
         }
         while ($this->state === ConnectionState::CLOSING) {
             $frame = (yield $this->transport->read());
             if ($frame instanceof ConnectionCloseOkFrame) {
                 (yield $this->transport->close());
                 (yield $this->onClose());
             }
         }
     } catch (ChannelClosedException $e) {
         (yield $this->onClose(SingleConnectionException::closedUnexpectedly($this->options, $e)));
     } catch (Throwable $e) {
         assert(Debug::dumpException('read-loop', $e));
         (yield $this->onClose($e));
     }
 }
Example #4
0
 /**
  * Perform the "open" phase of the handshake.
  *
  * @recoil-coroutine
  *
  * @param DuplexChannel     $frames  A channel over which frames are sent
  *                                   and received.
  * @param ConnectionOptions $options The options used when establishing
  *                                   the connection.
  */
 private function open(DuplexChannel $frames, ConnectionOptions $options) : Generator
 {
     (yield $frames->write(ConnectionOpenFrame::create($options->vhost())));
     try {
         $frame = (yield $frames->read());
     } catch (ChannelClosedException $e) {
         throw SingleConnectionException::authorizationFailed($options, $e);
     }
     if ($frame instanceof ConnectionCloseFrame) {
         if ($frame->replyCode === Constants::NOT_ALLOWED && $frame->classId === ConnectionOpenFrame::METHOD_ID >> 16 && $frame->methodId === (ConnectionOpenFrame::METHOD_ID & 0xff)) {
             throw SingleConnectionException::authorizationFailed($options);
         }
         throw SingleConnectionException::closedUnexpectedly($options);
     } elseif (!$frame instanceof ConnectionOpenOkFrame) {
         throw ProtocolException::unexpectedFrame($frame, 'expected ' . ConnectionOpenOkFrame::class);
     }
 }