Esempio n. 1
0
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
}
Esempio n. 2
0
func (channel *Channel) queueDeclare(method *amqp.QueueDeclare) *amqp.AMQPError {
	var classId, methodId = method.MethodIdentifier()
	// No name means generate a name
	if len(method.Queue) == 0 {
		method.Queue = util.RandomId()
	}

	// Check the name format
	var err = amqp.CheckExchangeOrQueueName(method.Queue)
	if err != nil {
		return amqp.NewSoftError(406, err.Error(), classId, methodId)
	}

	// If this is a passive request, do the appropriate checks and return
	if method.Passive {
		queue, found := channel.conn.server.queues[method.Queue]
		if found {
			if !method.NoWait {
				var qsize = uint32(queue.Len())
				var csize = queue.ActiveConsumerCount()
				channel.SendMethod(&amqp.QueueDeclareOk{method.Queue, qsize, csize})
			}
			channel.lastQueueName = method.Queue
			return nil
		}
		return amqp.NewSoftError(404, "Queue not found", classId, methodId)
	}

	// Create the new queue
	var connId = channel.conn.id
	if !method.Exclusive {
		connId = -1
	}
	var queue = queue.NewQueue(
		method.Queue,
		method.Durable,
		method.Exclusive,
		method.AutoDelete,
		method.Arguments,
		connId,
		channel.server.msgStore,
		channel.server.queueDeleter,
	)

	// If the new queue exists already, ensure the settings are the same. If it
	// doesn't, add it and optionally persist it
	existing, hasKey := channel.server.queues[queue.Name]
	if hasKey {
		if existing.ConnId != -1 && existing.ConnId != channel.conn.id {
			return amqp.NewSoftError(405, "Queue is locked to another connection", classId, methodId)
		}
		if !existing.EquivalentQueues(queue) {
			return amqp.NewSoftError(406, "Queue exists and is not equivalent to existing", classId, methodId)
		}
	} else {
		err = channel.server.addQueue(queue)
		if err != nil { // pragma: nocover
			return amqp.NewSoftError(500, "Error creating queue", classId, methodId)
		}
		// Persist
		if queue.Durable {
			queue.Persist(channel.server.db)
		}
	}

	channel.lastQueueName = method.Queue
	if !method.NoWait {
		channel.SendMethod(&amqp.QueueDeclareOk{queue.Name, uint32(0), uint32(0)})
	}
	return nil
}