package rabbitmq // // All credit to Mondo // import ( "errors" "sync" "github.com/google/uuid" amqp "github.com/rabbitmq/amqp091-go" ) type rabbitMQChannel struct { uuid string connection *amqp.Connection channel *amqp.Channel confirmPublish chan amqp.Confirmation mtx sync.Mutex } func newRabbitChannel(conn *amqp.Connection, prefetchCount int, prefetchGlobal bool, confirmPublish bool) (*rabbitMQChannel, error) { id, err := uuid.NewRandom() if err != nil { return nil, err } rabbitCh := &rabbitMQChannel{ uuid: id.String(), connection: conn, } if err := rabbitCh.Connect(prefetchCount, prefetchGlobal, confirmPublish); err != nil { return nil, err } return rabbitCh, nil } func (r *rabbitMQChannel) Connect(prefetchCount int, prefetchGlobal bool, confirmPublish bool) error { var err error r.channel, err = r.connection.Channel() if err != nil { return err } err = r.channel.Qos(prefetchCount, 0, prefetchGlobal) if err != nil { return err } if confirmPublish { r.confirmPublish = r.channel.NotifyPublish(make(chan amqp.Confirmation, 1)) err = r.channel.Confirm(false) if err != nil { return err } } return nil } func (r *rabbitMQChannel) Close() error { if r.channel == nil { return errors.New("channel is nil") } return r.channel.Close() } func (r *rabbitMQChannel) Publish(exchange, key string, message amqp.Publishing) error { if r.channel == nil { return errors.New("channel is nil") } if r.confirmPublish != nil { r.mtx.Lock() defer r.mtx.Unlock() } err := r.channel.Publish(exchange, key, false, false, message) if err != nil { return err } if r.confirmPublish != nil { confirmation, ok := <-r.confirmPublish if !ok { return errors.New("channel closed before could receive confirmation of publish") } if !confirmation.Ack { return errors.New("could not publish message, received nack from broker on confirmation") } } return nil } func (r *rabbitMQChannel) DeclareExchange(ex Exchange) error { return r.channel.ExchangeDeclare( ex.Name, // name string(ex.Type), // kind ex.Durable, // durable false, // autoDelete false, // internal false, // noWait nil, // args ) } func (r *rabbitMQChannel) DeclareDurableExchange(ex Exchange) error { return r.channel.ExchangeDeclare( ex.Name, // name string(ex.Type), // kind true, // durable false, // autoDelete false, // internal false, // noWait nil, // args ) } func (r *rabbitMQChannel) DeclareQueue(queue string, args amqp.Table) error { _, err := r.channel.QueueDeclare( queue, // name false, // durable true, // autoDelete false, // exclusive false, // noWait args, // args ) return err } func (r *rabbitMQChannel) DeclareDurableQueue(queue string, args amqp.Table) error { _, err := r.channel.QueueDeclare( queue, // name true, // durable false, // autoDelete false, // exclusive false, // noWait args, // args ) return err } func (r *rabbitMQChannel) DeclareReplyQueue(queue string) error { _, err := r.channel.QueueDeclare( queue, // name false, // durable true, // autoDelete true, // exclusive false, // noWait nil, // args ) return err } func (r *rabbitMQChannel) ConsumeQueue(queue string, autoAck bool) (<-chan amqp.Delivery, error) { return r.channel.Consume( queue, // queue r.uuid, // consumer autoAck, // autoAck false, // exclusive false, // nolocal false, // nowait nil, // args ) } func (r *rabbitMQChannel) BindQueue(queue, key, exchange string, args amqp.Table) error { return r.channel.QueueBind( queue, // name key, // key exchange, // exchange false, // noWait args, // args ) }