示例#1
0
 /**
  * Connect to an AMQP broker.
  *
  * @recoil-coroutine
  *
  * @param ConnectionOptions $options Options that configure the connection.
  *
  * @return Connection          The AMQP connection.
  * @throws ConnectionException The connection could not be established.
  */
 public function connect(ConnectionOptions $options) : Generator
 {
     try {
         return (yield Recoil::timeout($this->connectionTimeout($options), $this->connectAndHandshake($options)));
     } catch (ChannelClosedException $e) {
         throw SingleConnectionException::closedUnexpectedly($options, $e);
     } catch (TimeoutException $e) {
         throw SingleConnectionException::couldNotConnect($options, 'the connection timed out', $e);
     }
 }
示例#2
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));
     }
 }
示例#3
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);
     }
 }