/** * Appends AMQP protocol header to buffer. * * @param Buffer $buffer */ public function appendProtocolHeader(Buffer $buffer) { $buffer->append('AMQP'); $buffer->appendUint8(0); $buffer->appendUint8(0); $buffer->appendUint8(9); $buffer->appendUint8(1); }
/** * Reads data from stream into {@link readBuffer}. */ protected function read() { $s = @fread($this->stream, $this->frameMax); if (@feof($this->stream)) { throw new ClientException("Broken pipe or closed connection."); } $this->readBuffer->append($s); $this->lastRead = microtime(true); }
/** * Reads data from stream into {@link readBuffer}. */ protected function read() { $s = @fread($this->stream, $this->frameMax); if ($s === false) { $info = stream_get_meta_data($this->stream); if (isset($info["timed_out"]) && $info["timed_out"]) { throw new ClientException("Timeout reached while reading from stream."); } } if (@feof($this->stream)) { throw new ClientException("Broken pipe or closed connection."); } $this->readBuffer->append($s); $this->lastRead = microtime(true); }
public function consume($channel, $queue = '', $consumerTag = '', $noLocal = false, $noAck = false, $exclusive = false, $nowait = false, $arguments = []) { $buffer = new Buffer(); $buffer->appendUint16(60); $buffer->appendUint16(20); $buffer->appendInt16(0); $buffer->appendUint8(strlen($queue)); $buffer->append($queue); $buffer->appendUint8(strlen($consumerTag)); $buffer->append($consumerTag); $this->getWriter()->appendBits([$noLocal, $noAck, $exclusive, $nowait], $buffer); $this->getWriter()->appendTable($arguments, $buffer); $frame = new Protocol\MethodFrame(60, 20); $frame->channel = $channel; $frame->payloadSize = $buffer->getLength(); $frame->payload = $buffer; $this->getWriter()->appendFrame($frame, $this->getWriteBuffer()); $this->flushWriteBuffer(); return $this->awaitConsumeOk($channel); }
/** * Callback after channel-level frame has been received. * * @param AbstractFrame $frame */ public function onFrameReceived(AbstractFrame $frame) { if ($this->state === ChannelStateEnum::ERROR) { throw new ChannelException("Channel in error state."); } if ($this->state === ChannelStateEnum::CLOSED) { throw new ChannelException("Received frame #{$frame->type} on closed channel #{$this->channelId}."); } if ($frame instanceof MethodFrame) { if ($this->state === ChannelStateEnum::CLOSING && !$frame instanceof MethodChannelCloseOkFrame) { // drop frames in closing state return; } elseif ($this->state !== ChannelStateEnum::READY && !$frame instanceof MethodChannelCloseOkFrame) { $currentState = $this->state; $this->state = ChannelStateEnum::ERROR; if ($currentState === ChannelStateEnum::AWAITING_HEADER) { $msg = "Got method frame, expected header frame."; } elseif ($currentState === ChannelStateEnum::AWAITING_BODY) { $msg = "Got method frame, expected body frame."; } else { throw new \LogicException("Unhandled channel state."); } $this->client->disconnect(Constants::STATUS_UNEXPECTED_FRAME, $msg); throw new ChannelException("Unexpected frame: " . $msg); } if ($frame instanceof MethodChannelCloseOkFrame) { $this->state = ChannelStateEnum::CLOSED; if ($this->closeDeferred !== null) { $this->closeDeferred->resolve($this->channelId); } // break reference cycle, must be called after resolving promise unset($this->client); // break consumers' reference cycle $this->deliverCallbacks = []; } elseif ($frame instanceof MethodBasicReturnFrame) { $this->returnFrame = $frame; $this->state = ChannelStateEnum::AWAITING_HEADER; } elseif ($frame instanceof MethodBasicDeliverFrame) { $this->deliverFrame = $frame; $this->state = ChannelStateEnum::AWAITING_HEADER; } elseif ($frame instanceof MethodBasicAckFrame) { foreach ($this->ackCallbacks as $callback) { $callback($frame); } } elseif ($frame instanceof MethodBasicNackFrame) { foreach ($this->ackCallbacks as $callback) { $callback($frame); } } else { throw new ChannelException("Unhandled method frame " . get_class($frame) . "."); } } elseif ($frame instanceof ContentHeaderFrame) { if ($this->state === ChannelStateEnum::CLOSING) { // drop frames in closing state return; } elseif ($this->state !== ChannelStateEnum::AWAITING_HEADER) { $currentState = $this->state; $this->state = ChannelStateEnum::ERROR; if ($currentState === ChannelStateEnum::READY) { $msg = "Got header frame, expected method frame."; } elseif ($currentState === ChannelStateEnum::AWAITING_BODY) { $msg = "Got header frame, expected content frame."; } else { throw new \LogicException("Unhandled channel state."); } $this->client->disconnect(Constants::STATUS_UNEXPECTED_FRAME, $msg); throw new ChannelException("Unexpected frame: " . $msg); } $this->headerFrame = $frame; $this->bodySizeRemaining = $frame->bodySize; $this->state = ChannelStateEnum::AWAITING_BODY; } elseif ($frame instanceof ContentBodyFrame) { if ($this->state === ChannelStateEnum::CLOSING) { // drop frames in closing state return; } elseif ($this->state !== ChannelStateEnum::AWAITING_BODY) { $currentState = $this->state; $this->state = ChannelStateEnum::ERROR; if ($currentState === ChannelStateEnum::READY) { $msg = "Got body frame, expected method frame."; } elseif ($currentState === ChannelStateEnum::AWAITING_HEADER) { $msg = "Got body frame, expected header frame."; } else { throw new \LogicException("Unhandled channel state."); } $this->client->disconnect(Constants::STATUS_UNEXPECTED_FRAME, $msg); throw new ChannelException("Unexpected frame: " . $msg); } $this->bodyBuffer->append($frame->payload); $this->bodySizeRemaining -= $frame->payloadSize; if ($this->bodySizeRemaining < 0) { $this->state = ChannelStateEnum::ERROR; $this->client->disconnect(Constants::STATUS_SYNTAX_ERROR, "Body overflow, received " . -$this->bodySizeRemaining . " more bytes."); } elseif ($this->bodySizeRemaining === 0) { $this->state = ChannelStateEnum::READY; $this->onBodyComplete(); } } elseif ($frame instanceof HeartbeatFrame) { $this->client->disconnect(Constants::STATUS_UNEXPECTED_FRAME, "Got heartbeat on non-zero channel."); throw new ChannelException("Unexpected heartbeat frame."); } else { throw new ChannelException("Unhandled frame " . get_class($frame) . "."); } }
/** * Appends AMQP table/array field value to buffer. * * @param mixed $value * @param Buffer $buffer */ public function appendFieldValue($value, Buffer $buffer) { if (is_string($value)) { $buffer->appendUint8(Constants::FIELD_LONG_STRING); $buffer->appendUint32(strlen($value)); $buffer->append($value); } elseif (is_int($value)) { $buffer->appendUint8(Constants::FIELD_LONG_INT); $buffer->appendInt32($value); } elseif (is_bool($value)) { $buffer->appendUint8(Constants::FIELD_BOOLEAN); $buffer->appendUint8(intval($value)); } elseif (is_float($value)) { $buffer->appendUint8(Constants::FIELD_DOUBLE); $buffer->appendDouble($value); } elseif (is_array($value)) { if (array_keys($value) === range(0, count($value) - 1)) { // sequential array $buffer->appendUint8(Constants::FIELD_ARRAY); $this->appendArray($value, $buffer); } else { $buffer->appendUint8(Constants::FIELD_TABLE); $this->appendTable($value, $buffer); } } elseif (is_null($value)) { $buffer->appendUint8(Constants::FIELD_NULL); } elseif ($value instanceof \DateTime) { $buffer->appendUint8(Constants::FIELD_TIMESTAMP); $this->appendTimestamp($value, $buffer); } else { throw new ProtocolException("Unhandled value type '" . gettype($value) . "' " . (is_object($value) ? "(class " . get_class($value) . ")" : "") . "."); } }
/** * Callback after channel-level frame has been received. * * @param AbstractFrame $frame */ public function onFrameReceived(AbstractFrame $frame) { if ($this->state === ChannelStateEnum::ERROR) { throw new ChannelException("Channel in error state."); } if ($frame instanceof MethodFrame) { if ($this->state !== ChannelStateEnum::READY) { $currentState = $this->state; $this->state = ChannelStateEnum::ERROR; if ($currentState === ChannelStateEnum::AWAITING_HEADER) { $msg = "Got method frame, expected header frame."; } elseif ($currentState === ChannelStateEnum::AWAITING_BODY) { $msg = "Got method frame, expected body frame."; } else { throw new \LogicException("Unhandled channel state."); } $this->client->disconnect(Constants::STATUS_UNEXPECTED_FRAME, $msg); throw new ChannelException("Unexpected frame: " . $msg); } if (false) { // } elseif ($frame instanceof MethodConnectionStartFrame) { // } elseif ($frame instanceof MethodConnectionStartOkFrame) { // } elseif ($frame instanceof MethodConnectionSecureFrame) { // } elseif ($frame instanceof MethodConnectionSecureOkFrame) { // } elseif ($frame instanceof MethodConnectionTuneFrame) { // } elseif ($frame instanceof MethodConnectionTuneOkFrame) { // } elseif ($frame instanceof MethodConnectionOpenFrame) { // } elseif ($frame instanceof MethodConnectionOpenOkFrame) { // } elseif ($frame instanceof MethodConnectionCloseFrame) { // } elseif ($frame instanceof MethodConnectionCloseOkFrame) { // } elseif ($frame instanceof MethodConnectionBlockedFrame) { // } elseif ($frame instanceof MethodConnectionUnblockedFrame) { // } elseif ($frame instanceof MethodChannelOpenFrame) { // } elseif ($frame instanceof MethodChannelOpenOkFrame) { // } elseif ($frame instanceof MethodChannelFlowFrame) { // } elseif ($frame instanceof MethodChannelFlowOkFrame) { // } elseif ($frame instanceof MethodChannelCloseFrame) { // } elseif ($frame instanceof MethodChannelCloseOkFrame) { // } elseif ($frame instanceof MethodAccessRequestFrame) { // } elseif ($frame instanceof MethodAccessRequestOkFrame) { // } elseif ($frame instanceof MethodExchangeDeclareFrame) { // } elseif ($frame instanceof MethodExchangeDeclareOkFrame) { // } elseif ($frame instanceof MethodExchangeDeleteFrame) { // } elseif ($frame instanceof MethodExchangeDeleteOkFrame) { // } elseif ($frame instanceof MethodExchangeBindFrame) { // } elseif ($frame instanceof MethodExchangeBindOkFrame) { // } elseif ($frame instanceof MethodExchangeUnbindFrame) { // } elseif ($frame instanceof MethodExchangeUnbindOkFrame) { // } elseif ($frame instanceof MethodQueueDeclareFrame) { // } elseif ($frame instanceof MethodQueueDeclareOkFrame) { // } elseif ($frame instanceof MethodQueueBindFrame) { // } elseif ($frame instanceof MethodQueueBindOkFrame) { // } elseif ($frame instanceof MethodQueuePurgeFrame) { // } elseif ($frame instanceof MethodQueuePurgeOkFrame) { // } elseif ($frame instanceof MethodQueueDeleteFrame) { // } elseif ($frame instanceof MethodQueueDeleteOkFrame) { // } elseif ($frame instanceof MethodQueueUnbindFrame) { // } elseif ($frame instanceof MethodQueueUnbindOkFrame) { // } elseif ($frame instanceof MethodBasicQosFrame) { // } elseif ($frame instanceof MethodBasicQosOkFrame) { // } elseif ($frame instanceof MethodBasicConsumeFrame) { // } elseif ($frame instanceof MethodBasicConsumeOkFrame) { // } elseif ($frame instanceof MethodBasicCancelFrame) { // } elseif ($frame instanceof MethodBasicCancelOkFrame) { // } elseif ($frame instanceof MethodBasicPublishFrame) { } elseif ($frame instanceof MethodBasicReturnFrame) { $this->returnFrame = $frame; $this->state = ChannelStateEnum::AWAITING_HEADER; } elseif ($frame instanceof MethodBasicDeliverFrame) { $this->deliverFrame = $frame; $this->state = ChannelStateEnum::AWAITING_HEADER; // } elseif ($frame instanceof MethodBasicGetFrame) { // } elseif ($frame instanceof MethodBasicGetOkFrame) { // } elseif ($frame instanceof MethodBasicGetEmptyFrame) { // } elseif ($frame instanceof MethodBasicAckFrame) { // } elseif ($frame instanceof MethodBasicRejectFrame) { // } elseif ($frame instanceof MethodBasicRecoverAsyncFrame) { // } elseif ($frame instanceof MethodBasicRecoverFrame) { // } elseif ($frame instanceof MethodBasicRecoverOkFrame) { // } elseif ($frame instanceof MethodBasicNackFrame) { // } elseif ($frame instanceof MethodTxSelectFrame) { // } elseif ($frame instanceof MethodTxSelectOkFrame) { // } elseif ($frame instanceof MethodTxCommitFrame) { // } elseif ($frame instanceof MethodTxCommitOkFrame) { // } elseif ($frame instanceof MethodTxRollbackFrame) { // } elseif ($frame instanceof MethodTxRollbackOkFrame) { // } elseif ($frame instanceof MethodConfirmSelectFrame) { // } elseif ($frame instanceof MethodConfirmSelectOkFrame) { } else { throw new ChannelException("Unhandled method frame " . get_class($frame) . "."); } } elseif ($frame instanceof ContentHeaderFrame) { if ($this->state !== ChannelStateEnum::AWAITING_HEADER) { $currentState = $this->state; $this->state = ChannelStateEnum::ERROR; if ($currentState === ChannelStateEnum::READY) { $msg = "Got header frame, expected method frame."; } elseif ($currentState === ChannelStateEnum::AWAITING_BODY) { $msg = "Got header frame, expected content frame."; } else { throw new \LogicException("Unhandled channel state."); } $this->client->disconnect(Constants::STATUS_UNEXPECTED_FRAME, $msg); throw new ChannelException("Unexpected frame: " . $msg); } $this->headerFrame = $frame; $this->bodySizeRemaining = $frame->bodySize; $this->state = ChannelStateEnum::AWAITING_BODY; } elseif ($frame instanceof ContentBodyFrame) { if ($this->state !== ChannelStateEnum::AWAITING_BODY) { $currentState = $this->state; $this->state = ChannelStateEnum::ERROR; if ($currentState === ChannelStateEnum::READY) { $msg = "Got body frame, expected method frame."; } elseif ($currentState === ChannelStateEnum::AWAITING_HEADER) { $msg = "Got body frame, expected header frame."; } else { throw new \LogicException("Unhandled channel state."); } $this->client->disconnect(Constants::STATUS_UNEXPECTED_FRAME, $msg); throw new ChannelException("Unexpected frame: " . $msg); } $this->bodyBuffer->append($frame->payload); $this->bodySizeRemaining -= $frame->payloadSize; if ($this->bodySizeRemaining < 0) { $this->state = ChannelStateEnum::ERROR; $this->client->disconnect(Constants::STATUS_SYNTAX_ERROR, "Body overflow, received " . -$this->bodySizeRemaining . " more bytes."); } elseif ($this->bodySizeRemaining === 0) { $this->state = ChannelStateEnum::READY; $this->onBodyComplete(); } } elseif ($frame instanceof HeartbeatFrame) { $this->client->disconnect(Constants::STATUS_UNEXPECTED_FRAME, "Got heartbeat on non-zero channel."); throw new ChannelException("Unexpected heartbeat frame."); } else { throw new ChannelException("Unhandled frame " . get_class($frame) . "."); } }