func (channel *Channel) basicRoute(methodFrame amqp.MethodFrame) *amqp.AMQPError { switch method := methodFrame.(type) { case *amqp.BasicQos: return channel.basicQos(method) case *amqp.BasicRecover: return channel.basicRecover(method) case *amqp.BasicNack: return channel.basicNack(method) case *amqp.BasicConsume: return channel.basicConsume(method) case *amqp.BasicCancel: return channel.basicCancel(method) case *amqp.BasicCancelOk: return channel.basicCancelOk(method) case *amqp.BasicPublish: return channel.basicPublish(method) case *amqp.BasicGet: return channel.basicGet(method) case *amqp.BasicAck: return channel.basicAck(method) case *amqp.BasicReject: return channel.basicReject(method) } var classId, methodId = methodFrame.MethodIdentifier() return amqp.NewHardError(540, "Unable to route method frame", classId, methodId) }
func (channel *Channel) exchangeUnbind(method *amqp.ExchangeUnbind) *amqp.AMQPError { var classId, methodId = method.MethodIdentifier() return amqp.NewHardError(540, "Not implemented", classId, methodId) // if !method.NoWait { // channel.SendMethod(&amqp.ExchangeUnbindOk{}) // } }
func (channel *Channel) routeMethod(frame *amqp.WireFrame) *amqp.AMQPError { var methodReader = bytes.NewReader(frame.Payload) var methodFrame, err = amqp.ReadMethod(methodReader, channel.server.strictMode) if err != nil { return amqp.NewHardError(500, err.Error(), 0, 0) } var classId, methodId = methodFrame.MethodIdentifier() // If the method isn't closing related and we're closing, ignore the frames var closeChannel = classId == amqp.ClassIdChannel && (methodId == amqp.MethodIdChannelClose || methodId == amqp.MethodIdChannelCloseOk) var closeConnection = classId == amqp.ClassIdConnection && (methodId == amqp.MethodIdConnectionClose || methodId == amqp.MethodIdConnectionCloseOk) if channel.state == CH_STATE_CLOSING && !(closeChannel || closeConnection) { return nil } // Non-open method on an INIT-state channel is an error if channel.state == CH_STATE_INIT && (classId != 20 || methodId != 10) { return amqp.NewHardError( 503, "Non-Channel.Open method called on unopened channel", classId, methodId, ) } // Route // fmt.Println("Routing method: " + methodFrame.MethodName()) switch { case classId == 10: return channel.connectionRoute(channel.conn, methodFrame) case classId == 20: return channel.channelRoute(methodFrame) case classId == 40: return channel.exchangeRoute(methodFrame) case classId == 50: return channel.queueRoute(methodFrame) case classId == 60: return channel.basicRoute(methodFrame) case classId == 90: return channel.txRoute(methodFrame) default: return amqp.NewHardError(540, "Not implemented", classId, methodId) } return nil }
func (channel *Channel) txRoute(methodFrame amqp.MethodFrame) *amqp.AMQPError { switch method := methodFrame.(type) { case *amqp.TxSelect: return channel.txSelect(method) case *amqp.TxCommit: return channel.txCommit(method) case *amqp.TxRollback: return channel.txRollback(method) } var classId, methodId = methodFrame.MethodIdentifier() return amqp.NewHardError(540, "Unable to route method frame", classId, methodId) }
func (channel *Channel) exchangeRoute(methodFrame amqp.MethodFrame) *amqp.AMQPError { switch method := methodFrame.(type) { case *amqp.ExchangeDeclare: return channel.exchangeDeclare(method) case *amqp.ExchangeBind: return channel.exchangeBind(method) case *amqp.ExchangeUnbind: return channel.exchangeUnbind(method) case *amqp.ExchangeDelete: return channel.exchangeDelete(method) } var classId, methodId = methodFrame.MethodIdentifier() return amqp.NewHardError(540, "Not implemented", classId, methodId) }
func (channel *Channel) handleContentHeader(frame *amqp.WireFrame) *amqp.AMQPError { if channel.currentMessage == nil { return amqp.NewSoftError(500, "Unexpected content header frame!", 0, 0) } if channel.currentMessage.Header != nil { return amqp.NewSoftError(500, "Unexpected content header frame! Already saw header", 0, 0) } var headerFrame = &amqp.ContentHeaderFrame{} var err = headerFrame.Read(bytes.NewReader(frame.Payload), channel.server.strictMode) if err != nil { return amqp.NewHardError(500, "Error parsing header frame: "+err.Error(), 0, 0) } channel.currentMessage.Header = headerFrame return nil }
func NewFromMethod(method *amqp.ExchangeDeclare, system bool, exchangeDeleter chan *Exchange) (*Exchange, *amqp.AMQPError) { var classId, methodId = method.MethodIdentifier() var tp, err = ExchangeNameToType(method.Type) if err != nil || tp == EX_TYPE_HEADERS { return nil, amqp.NewHardError(503, "Bad exchange type", classId, methodId) } var ex = NewExchange( method.Exchange, tp, method.Durable, method.AutoDelete, method.Internal, method.Arguments, system, exchangeDeleter, ) return ex, nil }
func (channel *Channel) addConsumer(q *queue.Queue, method *amqp.BasicConsume) *amqp.AMQPError { var classId, methodId = method.MethodIdentifier() // Create consumer var consumer = consumer.NewConsumer( channel.server.msgStore, method.Arguments, channel, method.ConsumerTag, method.Exclusive, method.NoAck, method.NoLocal, q, q.Name, channel.defaultPrefetchSize, channel.defaultPrefetchCount, channel.conn.id, ) channel.consumerLock.Lock() defer channel.consumerLock.Unlock() // Make sure the doesn't exist on this channel _, found := channel.consumers[consumer.ConsumerTag] if found { return amqp.NewHardError( 530, fmt.Sprintf("Consumer tag already exists: %s", consumer.ConsumerTag), classId, methodId, ) } // Add the consumer to the queue, then channel code, err := q.AddConsumer(consumer, method.Exclusive) if err != nil { return amqp.NewSoftError(code, err.Error(), classId, methodId) } channel.consumers[consumer.ConsumerTag] = consumer consumer.Start() return nil }
func (channel *Channel) connectionRoute(conn *AMQPConnection, methodFrame amqp.MethodFrame) *amqp.AMQPError { switch method := methodFrame.(type) { case *amqp.ConnectionStartOk: return channel.connectionStartOk(conn, method) case *amqp.ConnectionTuneOk: return channel.connectionTuneOk(conn, method) case *amqp.ConnectionOpen: return channel.connectionOpen(conn, method) case *amqp.ConnectionClose: return channel.connectionClose(conn, method) case *amqp.ConnectionSecureOk: return channel.connectionSecureOk(conn, method) case *amqp.ConnectionCloseOk: return channel.connectionCloseOk(conn, method) case *amqp.ConnectionBlocked: return channel.connectionBlocked(conn, method) case *amqp.ConnectionUnblocked: return channel.connectionUnblocked(conn, method) } var classId, methodId = methodFrame.MethodIdentifier() return amqp.NewHardError(540, "Unable to route method frame", classId, methodId) }
func (channel *Channel) start() { if channel.id == 0 { channel.state = CH_STATE_OPEN go channel.startConnection() } else { go channel.startChannel() } // Receive method frames from the client and route them go func() { for { if channel.state == CH_STATE_CLOSED { break } var frame = <-channel.incoming var amqpErr *amqp.AMQPError = nil switch { case frame.FrameType == uint8(amqp.FrameMethod): amqpErr = channel.routeMethod(frame) case frame.FrameType == uint8(amqp.FrameHeader): if channel.state != CH_STATE_CLOSING { amqpErr = channel.handleContentHeader(frame) } case frame.FrameType == uint8(amqp.FrameBody): if channel.state != CH_STATE_CLOSING { amqpErr = channel.handleContentBody(frame) } default: amqpErr = amqp.NewHardError(500, "Unknown frame type", 0, 0) } if amqpErr != nil { channel.sendError(amqpErr) } } }() }
func (channel *Channel) connectionUnblocked(conn *AMQPConnection, method *amqp.ConnectionUnblocked) *amqp.AMQPError { return amqp.NewHardError(540, "Not implemented", 10, 61) }
func (channel *Channel) basicCancelOk(method *amqp.BasicCancelOk) *amqp.AMQPError { // TODO(MAY) var classId, methodId = method.MethodIdentifier() return amqp.NewHardError(540, "Not implemented", classId, methodId) }
func (channel *Channel) exchangeDeclare(method *amqp.ExchangeDeclare) *amqp.AMQPError { var classId, methodId = method.MethodIdentifier() // The client I'm using for testing thought declaring the empty exchange // was OK. Check later // if len(method.Exchange) > 0 && !method.Passive { // var msg = "The empty exchange name is reserved" // channel.channelErrorWithMethod(406, msg, classId, methodId) // return nil // } // Check the name format var err = amqp.CheckExchangeOrQueueName(method.Exchange) if err != nil { return amqp.NewSoftError(406, err.Error(), classId, methodId) } // Declare! var ex, amqpErr = exchange.NewFromMethod(method, false, channel.server.exchangeDeleter) if amqpErr != nil { return amqpErr } tp, err := exchange.ExchangeNameToType(method.Type) if err != nil || tp == exchange.EX_TYPE_HEADERS { return amqp.NewHardError(503, err.Error(), classId, methodId) } existing, hasKey := channel.server.exchanges[ex.Name] if !hasKey && method.Passive { return amqp.NewSoftError(404, "Exchange does not exist", classId, methodId) } if hasKey { // if diskLoad { // panic(fmt.Sprintf("Can't disk load a key that exists: %s", ex.Name)) // } if existing.ExType != ex.ExType { return amqp.NewHardError(530, "Cannot redeclare an exchange with a different type", classId, methodId) } if existing.EquivalentExchanges(ex) { if !method.NoWait { channel.SendMethod(&amqp.ExchangeDeclareOk{}) } return nil } // Not equivalent, error in passive mode if method.Passive { return amqp.NewSoftError(406, "Exchange with this name already exists", classId, methodId) } } if method.Passive { if !method.NoWait { channel.SendMethod(&amqp.ExchangeDeclareOk{}) } return nil } // outside of passive mode you can't create an exchange starting with // amq. if strings.HasPrefix(method.Exchange, "amq.") { return amqp.NewSoftError(403, "Exchange names starting with 'amq.' are reserved", classId, methodId) } err = channel.server.addExchange(ex) if err != nil { return amqp.NewSoftError(500, err.Error(), classId, methodId) } err = ex.Persist(channel.server.db) if err != nil { return amqp.NewSoftError(500, err.Error(), classId, methodId) } if !method.NoWait { channel.SendMethod(&amqp.ExchangeDeclareOk{}) } return nil }