remove builders (#15)
* remove builders --------- Signed-off-by: Gabriele Santomaggio <G.santomaggio@gmail.com>
This commit is contained in:
parent
5fc29f4968
commit
60e006b2a3
|
|
@ -1,93 +1,87 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
mq "github.com/rabbitmq/rabbitmq-amqp-go-client/rabbitmq_amqp"
|
"github.com/rabbitmq/rabbitmq-amqp-go-client/rabbitmq_amqp"
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Printf("Getting started with AMQP Go AMQP 1.0 Client\n")
|
fmt.Printf("Getting started with AMQP Go AMQP 1.0 Client\n")
|
||||||
chStatusChanged := make(chan *mq.StatusChanged, 1)
|
chStatusChanged := make(chan *rabbitmq_amqp.StatusChanged, 1)
|
||||||
|
|
||||||
go func(ch chan *mq.StatusChanged) {
|
go func(ch chan *rabbitmq_amqp.StatusChanged) {
|
||||||
for statusChanged := range ch {
|
for statusChanged := range ch {
|
||||||
fmt.Printf("Status changed from %d to %d\n", statusChanged.From, statusChanged.To)
|
fmt.Printf("%s\n", statusChanged)
|
||||||
}
|
}
|
||||||
}(chStatusChanged)
|
}(chStatusChanged)
|
||||||
|
|
||||||
amqpConnection := mq.NewAmqpConnection()
|
amqpConnection := rabbitmq_amqp.NewAmqpConnectionNotifyStatusChanged(chStatusChanged)
|
||||||
amqpConnection.NotifyStatusChange(chStatusChanged)
|
err := amqpConnection.Open(context.Background(), rabbitmq_amqp.NewConnectionSettings())
|
||||||
err := amqpConnection.Open(context.Background(), mq.NewConnectionSettings())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Printf("Error opening connection: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("AMQP Connection opened.\n")
|
fmt.Printf("AMQP Connection opened.\n")
|
||||||
management := amqpConnection.Management()
|
management := amqpConnection.Management()
|
||||||
queueSpec := management.Queue("getting_started_queue").
|
exchangeInfo, err := management.DeclareExchange(context.TODO(), &rabbitmq_amqp.ExchangeSpecification{
|
||||||
QueueType(mq.QueueType{Type: mq.Quorum}).
|
Name: "getting-started-exchange",
|
||||||
MaxLengthBytes(mq.CapacityGB(1))
|
})
|
||||||
exchangeSpec := management.Exchange("getting_started_exchange").
|
|
||||||
ExchangeType(mq.ExchangeType{Type: mq.Topic})
|
|
||||||
|
|
||||||
queueInfo, err := queueSpec.Declare(context.Background())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error declaring queue %s\n", err)
|
fmt.Printf("Error declaring exchange: %v\n", err)
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Printf("Queue %s created.\n", queueInfo.GetName())
|
|
||||||
|
|
||||||
exchangeInfo, err := exchangeSpec.Declare(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error declaring exchange %s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Printf("Exchange %s created.\n", exchangeInfo.GetName())
|
|
||||||
|
|
||||||
bindingSpec := management.Binding().SourceExchange(exchangeSpec).DestinationQueue(queueSpec).Key("routing-key")
|
|
||||||
|
|
||||||
err = bindingSpec.Bind(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error binding %s\n", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Binding between %s and %s created.\n", exchangeInfo.GetName(), queueInfo.GetName())
|
queueInfo, err := management.DeclareQueue(context.TODO(), &rabbitmq_amqp.QueueSpecification{
|
||||||
|
Name: "getting-started-queue",
|
||||||
|
QueueType: rabbitmq_amqp.QueueType{Type: rabbitmq_amqp.Quorum},
|
||||||
|
})
|
||||||
|
|
||||||
fmt.Println("Press any key to cleanup and exit")
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
|
||||||
_, _ = reader.ReadString('\n')
|
|
||||||
|
|
||||||
err = bindingSpec.Unbind(context.Background())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error unbinding %s\n", err)
|
fmt.Printf("Error declaring queue: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Binding between %s and %s deleted.\n", exchangeInfo.GetName(), queueInfo.GetName())
|
bindingPath, err := management.Bind(context.TODO(), &rabbitmq_amqp.BindingSpecification{
|
||||||
|
SourceExchange: exchangeInfo.Name(),
|
||||||
|
DestinationQueue: queueInfo.Name(),
|
||||||
|
BindingKey: "routing-key",
|
||||||
|
})
|
||||||
|
|
||||||
err = exchangeSpec.Delete(context.Background())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error deleting exchange %s\n", err)
|
fmt.Printf("Error binding: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = queueSpec.Delete(context.Background())
|
err = management.Unbind(context.TODO(), bindingPath)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Printf("Error unbinding: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = management.DeleteExchange(context.TODO(), exchangeInfo.Name())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error deleting exchange: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = management.DeleteQueue(context.TODO(), queueInfo.Name())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error deleting queue: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Printf("Queue %s deleted.\n", queueInfo.GetName())
|
|
||||||
|
|
||||||
err = amqpConnection.Close(context.Background())
|
err = amqpConnection.Close(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Printf("Error closing connection: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("AMQP Connection closed.\n")
|
fmt.Printf("AMQP Connection closed.\n")
|
||||||
// Wait for the status change to be printed
|
// Wait for the status change to be printed
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
|
||||||
close(chStatusChanged)
|
close(chStatusChanged)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
package rabbitmq_amqp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AddressBuilder struct {
|
||||||
|
queue *string
|
||||||
|
exchange *string
|
||||||
|
key *string
|
||||||
|
append *string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAddressBuilder() *AddressBuilder {
|
||||||
|
return &AddressBuilder{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AddressBuilder) Queue(queue string) *AddressBuilder {
|
||||||
|
a.queue = &queue
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AddressBuilder) Exchange(exchange string) *AddressBuilder {
|
||||||
|
a.exchange = &exchange
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AddressBuilder) Key(key string) *AddressBuilder {
|
||||||
|
a.key = &key
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AddressBuilder) Append(append string) *AddressBuilder {
|
||||||
|
a.append = &append
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AddressBuilder) Address() (string, error) {
|
||||||
|
if a.exchange == nil && a.queue == nil {
|
||||||
|
return "", errors.New("exchange or queue must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
urlAppend := ""
|
||||||
|
if !isStringNilOrEmpty(a.append) {
|
||||||
|
urlAppend = *a.append
|
||||||
|
}
|
||||||
|
if !isStringNilOrEmpty(a.exchange) && !isStringNilOrEmpty(a.queue) {
|
||||||
|
return "", errors.New("exchange and queue cannot be set together")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isStringNilOrEmpty(a.exchange) {
|
||||||
|
if !isStringNilOrEmpty(a.key) {
|
||||||
|
return "/" + exchanges + "/" + encodePathSegments(*a.exchange) + "/" + encodePathSegments(*a.key) + urlAppend, nil
|
||||||
|
}
|
||||||
|
return "/" + exchanges + "/" + encodePathSegments(*a.exchange) + urlAppend, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.queue == nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if isStringNilOrEmpty(a.queue) {
|
||||||
|
return "", errors.New("queue must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
return "/" + queues + "/" + encodePathSegments(*a.queue) + urlAppend, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodePathSegments takes a string and returns its percent-encoded representation.
|
||||||
|
func encodePathSegments(input string) string {
|
||||||
|
var encoded strings.Builder
|
||||||
|
|
||||||
|
// Iterate over each character in the input string
|
||||||
|
for _, char := range input {
|
||||||
|
// Check if the character is an unreserved character (i.e., it doesn't need encoding)
|
||||||
|
if isUnreserved(char) {
|
||||||
|
encoded.WriteRune(char) // Append as is
|
||||||
|
} else {
|
||||||
|
// Encode character To %HH format
|
||||||
|
encoded.WriteString(fmt.Sprintf("%%%02X", char))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoded.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode takes a percent-encoded string and returns its decoded representation.
|
||||||
|
func decode(input string) (string, error) {
|
||||||
|
// Use url.QueryUnescape which properly decodes percent-encoded strings
|
||||||
|
decoded, err := url.QueryUnescape(input)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return decoded, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// isUnreserved checks if a character is an unreserved character in percent encoding
|
||||||
|
// Unreserved characters are: A-Z, a-z, 0-9, -, ., _, ~
|
||||||
|
func isUnreserved(char rune) bool {
|
||||||
|
return (char >= 'A' && char <= 'Z') ||
|
||||||
|
(char >= 'a' && char <= 'z') ||
|
||||||
|
(char >= '0' && char <= '9') ||
|
||||||
|
char == '-' || char == '.' || char == '_' || char == '~'
|
||||||
|
}
|
||||||
|
|
||||||
|
func bindingPath() string {
|
||||||
|
return "/" + bindings
|
||||||
|
}
|
||||||
|
|
||||||
|
func bindingPathWithExchangeQueueKey(toQueue bool, sourceName, destinationName, key string) string {
|
||||||
|
sourceNameEncoded := encodePathSegments(sourceName)
|
||||||
|
destinationNameEncoded := encodePathSegments(destinationName)
|
||||||
|
keyEncoded := encodePathSegments(key)
|
||||||
|
destinationType := "dste"
|
||||||
|
if toQueue {
|
||||||
|
destinationType = "dstq"
|
||||||
|
}
|
||||||
|
format := "/%s/src=%s;%s=%s;key=%s;args="
|
||||||
|
return fmt.Sprintf(format, bindings, sourceNameEncoded, destinationType, destinationNameEncoded, keyEncoded)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
package rabbitmq_amqp
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Address builder test ", func() {
|
||||||
|
It("With exchange, queue and key should raise and error", func() {
|
||||||
|
addressBuilder := NewAddressBuilder()
|
||||||
|
Expect(addressBuilder).NotTo(BeNil())
|
||||||
|
Expect(addressBuilder).To(BeAssignableToTypeOf(&AddressBuilder{}))
|
||||||
|
addressBuilder.Queue("queue").Exchange("exchange").Key("key")
|
||||||
|
_, err := addressBuilder.Address()
|
||||||
|
Expect(err).NotTo(BeNil())
|
||||||
|
Expect(err.Error()).To(Equal("exchange and queue cannot be set together"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Without exchange and queue should raise and error", func() {
|
||||||
|
addressBuilder := NewAddressBuilder()
|
||||||
|
Expect(addressBuilder).NotTo(BeNil())
|
||||||
|
Expect(addressBuilder).To(BeAssignableToTypeOf(&AddressBuilder{}))
|
||||||
|
_, err := addressBuilder.Address()
|
||||||
|
Expect(err).NotTo(BeNil())
|
||||||
|
Expect(err.Error()).To(Equal("exchange or queue must be set"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("With exchange and key should return address", func() {
|
||||||
|
addressBuilder := NewAddressBuilder()
|
||||||
|
Expect(addressBuilder).NotTo(BeNil())
|
||||||
|
Expect(addressBuilder).To(BeAssignableToTypeOf(&AddressBuilder{}))
|
||||||
|
addressBuilder.Exchange("my_exchange").Key("my_key")
|
||||||
|
address, err := addressBuilder.Address()
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(address).To(Equal("/exchanges/my_exchange/my_key"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("With exchange should return address", func() {
|
||||||
|
addressBuilder := NewAddressBuilder()
|
||||||
|
Expect(addressBuilder).NotTo(BeNil())
|
||||||
|
Expect(addressBuilder).To(BeAssignableToTypeOf(&AddressBuilder{}))
|
||||||
|
addressBuilder.Exchange("my_exchange")
|
||||||
|
address, err := addressBuilder.Address()
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(address).To(Equal("/exchanges/my_exchange"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("With exchange and key with names to encode should return the encoded address", func() {
|
||||||
|
addressBuilder := NewAddressBuilder()
|
||||||
|
Expect(addressBuilder).NotTo(BeNil())
|
||||||
|
Expect(addressBuilder).To(BeAssignableToTypeOf(&AddressBuilder{}))
|
||||||
|
addressBuilder.Exchange("my_ exchange/()").Key("my_key ")
|
||||||
|
address, err := addressBuilder.Address()
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(address).To(Equal("/exchanges/my_%20exchange%2F%28%29/my_key%20"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("With queue should return address", func() {
|
||||||
|
addressBuilder := NewAddressBuilder()
|
||||||
|
Expect(addressBuilder).NotTo(BeNil())
|
||||||
|
Expect(addressBuilder).To(BeAssignableToTypeOf(&AddressBuilder{}))
|
||||||
|
addressBuilder.Queue("my_queue>")
|
||||||
|
address, err := addressBuilder.Address()
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(address).To(Equal("/queues/my_queue%3E"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("With queue and append should return address", func() {
|
||||||
|
addressBuilder := NewAddressBuilder()
|
||||||
|
Expect(addressBuilder).NotTo(BeNil())
|
||||||
|
Expect(addressBuilder).To(BeAssignableToTypeOf(&AddressBuilder{}))
|
||||||
|
addressBuilder.Queue("my_queue").Append("/messages")
|
||||||
|
address, err := addressBuilder.Address()
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(address).To(Equal("/queues/my_queue/messages"))
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
@ -20,48 +20,36 @@ func newAMQPBinding(management *AmqpManagement) *AMQPBinding {
|
||||||
return &AMQPBinding{management: management}
|
return &AMQPBinding{management: management}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *AMQPBinding) Key(bindingKey string) IBindingSpecification {
|
func (b *AMQPBinding) BindingKey(bindingKey string) {
|
||||||
b.bindingKey = bindingKey
|
b.bindingKey = bindingKey
|
||||||
return b
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *AMQPBinding) SourceExchange(exchangeSpec IExchangeSpecification) IBindingSpecification {
|
func (b *AMQPBinding) SourceExchange(sourceName string) {
|
||||||
b.sourceName = exchangeSpec.GetName()
|
if len(sourceName) > 0 {
|
||||||
|
b.sourceName = sourceName
|
||||||
b.toQueue = false
|
b.toQueue = false
|
||||||
return b
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *AMQPBinding) SourceExchangeName(exchangeName string) IBindingSpecification {
|
func (b *AMQPBinding) DestinationExchange(destinationName string) {
|
||||||
b.sourceName = exchangeName
|
if len(destinationName) > 0 {
|
||||||
|
b.destinationName = destinationName
|
||||||
b.toQueue = false
|
b.toQueue = false
|
||||||
return b
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *AMQPBinding) DestinationExchange(exchangeSpec IExchangeInfo) IBindingSpecification {
|
func (b *AMQPBinding) DestinationQueue(queueName string) {
|
||||||
b.destinationName = exchangeSpec.GetName()
|
if len(queueName) > 0 {
|
||||||
b.toQueue = false
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *AMQPBinding) DestinationExchangeName(exchangeName string) IBindingSpecification {
|
|
||||||
b.destinationName = exchangeName
|
|
||||||
b.toQueue = false
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *AMQPBinding) DestinationQueue(queueSpec IQueueSpecification) IBindingSpecification {
|
|
||||||
b.destinationName = queueSpec.GetName()
|
|
||||||
b.toQueue = true
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *AMQPBinding) DestinationQueueName(queueName string) IBindingSpecification {
|
|
||||||
b.destinationName = queueName
|
b.destinationName = queueName
|
||||||
b.toQueue = true
|
b.toQueue = true
|
||||||
return b
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *AMQPBinding) Bind(ctx context.Context) error {
|
// Bind creates a binding between an exchange and a queue or exchange
|
||||||
|
// with the specified binding key.
|
||||||
|
// Returns the binding path that can be used to unbind the binding.
|
||||||
|
// Given a virtual host, the binding path is unique.
|
||||||
|
func (b *AMQPBinding) Bind(ctx context.Context) (string, error) {
|
||||||
path := bindingPath()
|
path := bindingPath()
|
||||||
kv := make(map[string]any)
|
kv := make(map[string]any)
|
||||||
kv["binding_key"] = b.bindingKey
|
kv["binding_key"] = b.bindingKey
|
||||||
|
|
@ -69,11 +57,14 @@ func (b *AMQPBinding) Bind(ctx context.Context) error {
|
||||||
kv["destination_queue"] = b.destinationName
|
kv["destination_queue"] = b.destinationName
|
||||||
kv["arguments"] = make(map[string]any)
|
kv["arguments"] = make(map[string]any)
|
||||||
_, err := b.management.Request(ctx, kv, path, commandPost, []int{responseCode204})
|
_, err := b.management.Request(ctx, kv, path, commandPost, []int{responseCode204})
|
||||||
return err
|
bindingPathWithExchangeQueueKey := bindingPathWithExchangeQueueKey(b.toQueue, b.sourceName, b.destinationName, b.bindingKey)
|
||||||
|
return bindingPathWithExchangeQueueKey, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *AMQPBinding) Unbind(ctx context.Context) error {
|
// Unbind removes a binding between an exchange and a queue or exchange
|
||||||
bindingPathWithExchangeQueueKey := bindingPathWithExchangeQueueKey(b.toQueue, b.sourceName, b.destinationName, b.bindingKey)
|
// with the specified binding key.
|
||||||
_, err := b.management.Request(ctx, amqp.Null{}, bindingPathWithExchangeQueueKey, commandDelete, []int{responseCode204})
|
// The bindingPath is the unique path that was returned when the binding was created.
|
||||||
|
func (b *AMQPBinding) Unbind(ctx context.Context, bindingPath string) error {
|
||||||
|
_, err := b.management.Request(ctx, amqp.Null{}, bindingPath, commandDelete, []int{responseCode204})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,26 +28,30 @@ var _ = Describe("AMQP Bindings test ", func() {
|
||||||
It("AMQP Bindings between Exchange and Queue Should succeed", func() {
|
It("AMQP Bindings between Exchange and Queue Should succeed", func() {
|
||||||
const exchangeName = "Exchange_AMQP Bindings between Exchange and Queue should uccess"
|
const exchangeName = "Exchange_AMQP Bindings between Exchange and Queue should uccess"
|
||||||
const queueName = "Queue_AMQP Bindings between Exchange and Queue should succeed"
|
const queueName = "Queue_AMQP Bindings between Exchange and Queue should succeed"
|
||||||
exchangeSpec := management.Exchange(exchangeName)
|
exchangeInfo, err := management.DeclareExchange(context.TODO(), &ExchangeSpecification{
|
||||||
exchangeInfo, err := exchangeSpec.Declare(context.TODO())
|
Name: exchangeName,
|
||||||
|
})
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(exchangeInfo).NotTo(BeNil())
|
Expect(exchangeInfo).NotTo(BeNil())
|
||||||
Expect(exchangeInfo.GetName()).To(Equal(exchangeName))
|
Expect(exchangeInfo.Name()).To(Equal(exchangeName))
|
||||||
|
|
||||||
queueSpec := management.Queue(queueName)
|
queueInfo, err := management.DeclareQueue(context.TODO(), &QueueSpecification{
|
||||||
queueInfo, err := queueSpec.Declare(context.TODO())
|
Name: queueName,
|
||||||
|
})
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(queueInfo).NotTo(BeNil())
|
Expect(queueInfo).NotTo(BeNil())
|
||||||
Expect(queueInfo.GetName()).To(Equal(queueName))
|
Expect(queueInfo.Name()).To(Equal(queueName))
|
||||||
|
bindingPath, err := management.Bind(context.TODO(), &BindingSpecification{
|
||||||
bindingSpec := management.Binding().SourceExchange(exchangeSpec).DestinationQueue(queueSpec).Key("routing-key")
|
SourceExchange: exchangeName,
|
||||||
err = bindingSpec.Bind(context.TODO())
|
DestinationQueue: queueName,
|
||||||
|
BindingKey: "routing-key",
|
||||||
|
})
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err = bindingSpec.Unbind(context.TODO())
|
err = management.Unbind(context.TODO(), bindingPath)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err = exchangeSpec.Delete(context.TODO())
|
err = management.DeleteExchange(context.TODO(), exchangeName)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err = queueSpec.Delete(context.TODO())
|
err = management.DeleteQueue(context.TODO(), queueName)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -2,131 +2,17 @@ package rabbitmq_amqp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
|
||||||
"fmt"
|
|
||||||
"github.com/Azure/go-amqp"
|
"github.com/Azure/go-amqp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConnectionSettings struct {
|
//func (c *ConnectionSettings) UseSsl(value bool) {
|
||||||
host string
|
// c.UseSsl = value
|
||||||
port int
|
// if value {
|
||||||
user string
|
// c.Scheme = "amqps"
|
||||||
password string
|
// } else {
|
||||||
virtualHost string
|
// c.Scheme = "amqp"
|
||||||
scheme string
|
// }
|
||||||
containerId string
|
//}
|
||||||
useSsl bool
|
|
||||||
tlsConfig *tls.Config
|
|
||||||
saslMechanism TSaslMechanism
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) GetSaslMechanism() TSaslMechanism {
|
|
||||||
return c.saslMechanism
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) SaslMechanism(mechanism SaslMechanism) IConnectionSettings {
|
|
||||||
c.saslMechanism = mechanism.Type
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) TlsConfig(config *tls.Config) IConnectionSettings {
|
|
||||||
c.tlsConfig = config
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) GetTlsConfig() *tls.Config {
|
|
||||||
return c.tlsConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) Port(port int) IConnectionSettings {
|
|
||||||
c.port = port
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) User(userName string) IConnectionSettings {
|
|
||||||
c.user = userName
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) Password(password string) IConnectionSettings {
|
|
||||||
c.password = password
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) VirtualHost(virtualHost string) IConnectionSettings {
|
|
||||||
c.virtualHost = virtualHost
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) ContainerId(containerId string) IConnectionSettings {
|
|
||||||
c.containerId = containerId
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) GetHost() string {
|
|
||||||
return c.host
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) Host(hostName string) IConnectionSettings {
|
|
||||||
c.host = hostName
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) GetPort() int {
|
|
||||||
return c.port
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) GetUser() string {
|
|
||||||
return c.user
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) GetPassword() string {
|
|
||||||
return c.password
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) GetVirtualHost() string {
|
|
||||||
return c.virtualHost
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) GetScheme() string {
|
|
||||||
return c.scheme
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) GetContainerId() string {
|
|
||||||
return c.containerId
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) UseSsl(value bool) IConnectionSettings {
|
|
||||||
c.useSsl = value
|
|
||||||
if value {
|
|
||||||
c.scheme = "amqps"
|
|
||||||
} else {
|
|
||||||
c.scheme = "amqp"
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) IsSsl() bool {
|
|
||||||
return c.useSsl
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) BuildAddress() string {
|
|
||||||
return c.scheme + "://" + c.host + ":" + fmt.Sprint(c.port)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewConnectionSettings() IConnectionSettings {
|
|
||||||
return &ConnectionSettings{
|
|
||||||
host: "localhost",
|
|
||||||
port: 5672,
|
|
||||||
user: "guest",
|
|
||||||
password: "guest",
|
|
||||||
virtualHost: "/",
|
|
||||||
scheme: "amqp",
|
|
||||||
containerId: "amqp-go-client",
|
|
||||||
useSsl: false,
|
|
||||||
tlsConfig: nil,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AmqpConnection struct {
|
type AmqpConnection struct {
|
||||||
Connection *amqp.Conn
|
Connection *amqp.Conn
|
||||||
|
|
@ -134,10 +20,15 @@ type AmqpConnection struct {
|
||||||
lifeCycle *LifeCycle
|
lifeCycle *LifeCycle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Management returns the management interface for the connection.
|
||||||
|
// See IManagement interface.
|
||||||
func (a *AmqpConnection) Management() IManagement {
|
func (a *AmqpConnection) Management() IManagement {
|
||||||
return a.management
|
return a.management
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAmqpConnection creates a new AmqpConnection
|
||||||
|
// with a new AmqpManagement and a new LifeCycle.
|
||||||
|
// Returns a pointer to the new AmqpConnection
|
||||||
func NewAmqpConnection() IConnection {
|
func NewAmqpConnection() IConnection {
|
||||||
return &AmqpConnection{
|
return &AmqpConnection{
|
||||||
management: NewAmqpManagement(),
|
management: NewAmqpManagement(),
|
||||||
|
|
@ -145,20 +36,36 @@ func NewAmqpConnection() IConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpConnection) Open(ctx context.Context, connectionSettings IConnectionSettings) error {
|
// NewAmqpConnectionNotifyStatusChanged creates a new AmqpConnection
|
||||||
|
// with a new AmqpManagement and a new LifeCycle
|
||||||
|
// and sets the channel for status changes.
|
||||||
|
// Returns a pointer to the new AmqpConnection
|
||||||
|
func NewAmqpConnectionNotifyStatusChanged(channel chan *StatusChanged) IConnection {
|
||||||
|
lifeCycle := NewLifeCycle()
|
||||||
|
lifeCycle.chStatusChanged = channel
|
||||||
|
return &AmqpConnection{
|
||||||
|
management: NewAmqpManagement(),
|
||||||
|
lifeCycle: lifeCycle,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open opens a connection to the AMQP 1.0 server.
|
||||||
|
// using the provided connectionSettings and the AMQPLite library.
|
||||||
|
// Setups the connection and the management interface.
|
||||||
|
func (a *AmqpConnection) Open(ctx context.Context, connectionSettings *ConnectionSettings) error {
|
||||||
sASLType := amqp.SASLTypeAnonymous()
|
sASLType := amqp.SASLTypeAnonymous()
|
||||||
switch connectionSettings.GetSaslMechanism() {
|
switch connectionSettings.SaslMechanism {
|
||||||
case Plain:
|
case Plain:
|
||||||
sASLType = amqp.SASLTypePlain(connectionSettings.GetUser(), connectionSettings.GetPassword())
|
sASLType = amqp.SASLTypePlain(connectionSettings.User, connectionSettings.Password)
|
||||||
case External:
|
case External:
|
||||||
sASLType = amqp.SASLTypeExternal("")
|
sASLType = amqp.SASLTypeExternal("")
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := amqp.Dial(ctx, connectionSettings.BuildAddress(), &amqp.ConnOptions{
|
conn, err := amqp.Dial(ctx, connectionSettings.BuildAddress(), &amqp.ConnOptions{
|
||||||
ContainerID: connectionSettings.GetContainerId(),
|
ContainerID: connectionSettings.ContainerId,
|
||||||
SASLType: sASLType,
|
SASLType: sASLType,
|
||||||
HostName: connectionSettings.GetVirtualHost(),
|
HostName: connectionSettings.VirtualHost,
|
||||||
TLSConfig: connectionSettings.GetTlsConfig(),
|
TLSConfig: connectionSettings.TlsConfig,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -188,6 +95,6 @@ func (a *AmqpConnection) NotifyStatusChange(channel chan *StatusChanged) {
|
||||||
a.lifeCycle.chStatusChanged = channel
|
a.lifeCycle.chStatusChanged = channel
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpConnection) GetStatus() int {
|
func (a *AmqpConnection) Status() int {
|
||||||
return a.lifeCycle.Status()
|
return a.lifeCycle.Status()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ var _ = Describe("AMQP Connection Test", func() {
|
||||||
|
|
||||||
connectionSettings := NewConnectionSettings()
|
connectionSettings := NewConnectionSettings()
|
||||||
Expect(connectionSettings).NotTo(BeNil())
|
Expect(connectionSettings).NotTo(BeNil())
|
||||||
connectionSettings.SaslMechanism(SaslMechanism{Type: Anonymous})
|
connectionSettings.SaslMechanism = Anonymous
|
||||||
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
||||||
|
|
||||||
err := amqpConnection.Open(context.Background(), connectionSettings)
|
err := amqpConnection.Open(context.Background(), connectionSettings)
|
||||||
|
|
@ -32,7 +32,7 @@ var _ = Describe("AMQP Connection Test", func() {
|
||||||
connectionSettings := NewConnectionSettings()
|
connectionSettings := NewConnectionSettings()
|
||||||
Expect(connectionSettings).NotTo(BeNil())
|
Expect(connectionSettings).NotTo(BeNil())
|
||||||
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
||||||
connectionSettings.SaslMechanism(SaslMechanism{Type: Plain})
|
connectionSettings.SaslMechanism = Plain
|
||||||
|
|
||||||
err := amqpConnection.Open(context.Background(), connectionSettings)
|
err := amqpConnection.Open(context.Background(), connectionSettings)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
|
@ -40,28 +40,32 @@ var _ = Describe("AMQP Connection Test", func() {
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Connection should fail due of wrong port", func() {
|
It("AMQP Connection should fail due of wrong Port", func() {
|
||||||
amqpConnection := NewAmqpConnection()
|
amqpConnection := NewAmqpConnection()
|
||||||
Expect(amqpConnection).NotTo(BeNil())
|
Expect(amqpConnection).NotTo(BeNil())
|
||||||
Expect(amqpConnection).To(BeAssignableToTypeOf(&AmqpConnection{}))
|
Expect(amqpConnection).To(BeAssignableToTypeOf(&AmqpConnection{}))
|
||||||
connectionSettings := NewConnectionSettings()
|
connectionSettings := &ConnectionSettings{
|
||||||
|
Host: "localhost",
|
||||||
|
Port: 1234,
|
||||||
|
}
|
||||||
Expect(connectionSettings).NotTo(BeNil())
|
Expect(connectionSettings).NotTo(BeNil())
|
||||||
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
||||||
connectionSettings.Host("localhost").Port(1234)
|
|
||||||
|
|
||||||
err := amqpConnection.Open(context.Background(), connectionSettings)
|
err := amqpConnection.Open(context.Background(), connectionSettings)
|
||||||
Expect(err).NotTo(BeNil())
|
Expect(err).NotTo(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Connection should fail due of wrong host", func() {
|
It("AMQP Connection should fail due of wrong Host", func() {
|
||||||
amqpConnection := NewAmqpConnection()
|
amqpConnection := NewAmqpConnection()
|
||||||
Expect(amqpConnection).NotTo(BeNil())
|
Expect(amqpConnection).NotTo(BeNil())
|
||||||
Expect(amqpConnection).To(BeAssignableToTypeOf(&AmqpConnection{}))
|
Expect(amqpConnection).To(BeAssignableToTypeOf(&AmqpConnection{}))
|
||||||
|
|
||||||
connectionSettings := NewConnectionSettings()
|
connectionSettings := &ConnectionSettings{
|
||||||
|
Host: "wronghost",
|
||||||
|
Port: 5672,
|
||||||
|
}
|
||||||
Expect(connectionSettings).NotTo(BeNil())
|
Expect(connectionSettings).NotTo(BeNil())
|
||||||
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
||||||
connectionSettings.Host("wronghost").Port(5672)
|
|
||||||
|
|
||||||
err := amqpConnection.Open(context.Background(), connectionSettings)
|
err := amqpConnection.Open(context.Background(), connectionSettings)
|
||||||
Expect(err).NotTo(BeNil())
|
Expect(err).NotTo(BeNil())
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ func newAmqpExchangeInfo(name string) IExchangeInfo {
|
||||||
return &AmqpExchangeInfo{name: name}
|
return &AmqpExchangeInfo{name: name}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpExchangeInfo) GetName() string {
|
func (a *AmqpExchangeInfo) Name() string {
|
||||||
return a.name
|
return a.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,22 +34,24 @@ func newAmqpExchange(management *AmqpManagement, name string) *AmqpExchange {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *AmqpExchange) Declare(ctx context.Context) (IExchangeInfo, error) {
|
func (e *AmqpExchange) Declare(ctx context.Context) (IExchangeInfo, error) {
|
||||||
path := exchangePath(e.name)
|
path, err := NewAddressBuilder().Exchange(e.name).Address()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
kv := make(map[string]any)
|
kv := make(map[string]any)
|
||||||
kv["auto_delete"] = e.isAutoDelete
|
kv["auto_delete"] = e.isAutoDelete
|
||||||
kv["durable"] = true
|
kv["durable"] = true
|
||||||
kv["type"] = e.exchangeType.String()
|
kv["type"] = e.exchangeType.String()
|
||||||
kv["arguments"] = e.arguments
|
kv["arguments"] = e.arguments
|
||||||
_, err := e.management.Request(ctx, kv, path, commandPut, []int{responseCode204, responseCode201, responseCode409})
|
_, err = e.management.Request(ctx, kv, path, commandPut, []int{responseCode204, responseCode201, responseCode409})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return newAmqpExchangeInfo(e.name), nil
|
return newAmqpExchangeInfo(e.name), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *AmqpExchange) AutoDelete(isAutoDelete bool) IExchangeSpecification {
|
func (e *AmqpExchange) AutoDelete(isAutoDelete bool) {
|
||||||
e.isAutoDelete = isAutoDelete
|
e.isAutoDelete = isAutoDelete
|
||||||
return e
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *AmqpExchange) IsAutoDelete() bool {
|
func (e *AmqpExchange) IsAutoDelete() bool {
|
||||||
|
|
@ -57,20 +59,24 @@ func (e *AmqpExchange) IsAutoDelete() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *AmqpExchange) Delete(ctx context.Context) error {
|
func (e *AmqpExchange) Delete(ctx context.Context) error {
|
||||||
path := exchangePath(e.name)
|
path, err := NewAddressBuilder().Exchange(e.name).Address()
|
||||||
_, err := e.management.Request(ctx, amqp.Null{}, path, commandDelete, []int{responseCode204})
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = e.management.Request(ctx, amqp.Null{}, path, commandDelete, []int{responseCode204})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *AmqpExchange) ExchangeType(exchangeType ExchangeType) IExchangeSpecification {
|
func (e *AmqpExchange) ExchangeType(exchangeType ExchangeType) {
|
||||||
|
if len(exchangeType.Type) > 0 {
|
||||||
e.exchangeType = exchangeType
|
e.exchangeType = exchangeType
|
||||||
return e
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *AmqpExchange) GetExchangeType() TExchangeType {
|
func (e *AmqpExchange) GetExchangeType() TExchangeType {
|
||||||
return e.exchangeType.Type
|
return e.exchangeType.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *AmqpExchange) GetName() string {
|
func (e *AmqpExchange) Name() string {
|
||||||
return e.name
|
return e.name
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,34 +28,40 @@ var _ = Describe("AMQP Exchange test ", func() {
|
||||||
|
|
||||||
It("AMQP Exchange Declare with Default and Delete should succeed", func() {
|
It("AMQP Exchange Declare with Default and Delete should succeed", func() {
|
||||||
const exchangeName = "AMQP Exchange Declare and Delete with Default should succeed"
|
const exchangeName = "AMQP Exchange Declare and Delete with Default should succeed"
|
||||||
exchangeSpec := management.Exchange(exchangeName)
|
exchangeInfo, err := management.DeclareExchange(context.TODO(), &ExchangeSpecification{
|
||||||
exchangeInfo, err := exchangeSpec.Declare(context.TODO())
|
Name: exchangeName,
|
||||||
|
})
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(exchangeInfo).NotTo(BeNil())
|
Expect(exchangeInfo).NotTo(BeNil())
|
||||||
Expect(exchangeInfo.GetName()).To(Equal(exchangeName))
|
Expect(exchangeInfo.Name()).To(Equal(exchangeName))
|
||||||
err = exchangeSpec.Delete(context.TODO())
|
err = management.DeleteExchange(context.TODO(), exchangeName)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Exchange Declare with Topic and Delete should succeed", func() {
|
It("AMQP Exchange Declare with Topic and Delete should succeed", func() {
|
||||||
const exchangeName = "AMQP Exchange Declare with Topic and Delete should succeed"
|
const exchangeName = "AMQP Exchange Declare with Topic and Delete should succeed"
|
||||||
exchangeSpec := management.Exchange(exchangeName).ExchangeType(ExchangeType{Topic})
|
exchangeInfo, err := management.DeclareExchange(context.TODO(), &ExchangeSpecification{
|
||||||
exchangeInfo, err := exchangeSpec.Declare(context.TODO())
|
Name: exchangeName,
|
||||||
|
ExchangeType: ExchangeType{Topic},
|
||||||
|
})
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(exchangeInfo).NotTo(BeNil())
|
Expect(exchangeInfo).NotTo(BeNil())
|
||||||
Expect(exchangeInfo.GetName()).To(Equal(exchangeName))
|
Expect(exchangeInfo.Name()).To(Equal(exchangeName))
|
||||||
err = exchangeSpec.Delete(context.TODO())
|
err = management.DeleteExchange(context.TODO(), exchangeName)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Exchange Declare with FanOut and Delete should succeed", func() {
|
It("AMQP Exchange Declare with FanOut and Delete should succeed", func() {
|
||||||
const exchangeName = "AMQP Exchange Declare with FanOut and Delete should succeed"
|
const exchangeName = "AMQP Exchange Declare with FanOut and Delete should succeed"
|
||||||
exchangeSpec := management.Exchange(exchangeName).ExchangeType(ExchangeType{FanOut})
|
//exchangeSpec := management.Exchange(exchangeName).ExchangeType(ExchangeType{FanOut})
|
||||||
exchangeInfo, err := exchangeSpec.Declare(context.TODO())
|
exchangeInfo, err := management.DeclareExchange(context.TODO(), &ExchangeSpecification{
|
||||||
|
Name: exchangeName,
|
||||||
|
ExchangeType: ExchangeType{FanOut},
|
||||||
|
})
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(exchangeInfo).NotTo(BeNil())
|
Expect(exchangeInfo).NotTo(BeNil())
|
||||||
Expect(exchangeInfo.GetName()).To(Equal(exchangeName))
|
Expect(exchangeInfo.Name()).To(Equal(exchangeName))
|
||||||
err = exchangeSpec.Delete(context.TODO())
|
err = management.DeleteExchange(context.TODO(), exchangeName)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -22,14 +22,6 @@ type AmqpManagement struct {
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpManagement) Binding() IBindingSpecification {
|
|
||||||
return newAMQPBinding(a)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AmqpManagement) Exchange(exchangeName string) IExchangeSpecification {
|
|
||||||
return newAmqpExchange(a, exchangeName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAmqpManagement() *AmqpManagement {
|
func NewAmqpManagement() *AmqpManagement {
|
||||||
return &AmqpManagement{
|
return &AmqpManagement{
|
||||||
lifeCycle: NewLifeCycle(),
|
lifeCycle: NewLifeCycle(),
|
||||||
|
|
@ -201,12 +193,65 @@ func (a *AmqpManagement) request(ctx context.Context, id string, body any, path
|
||||||
return make(map[string]any), nil
|
return make(map[string]any), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpManagement) Queue(queueName string) IQueueSpecification {
|
func (a *AmqpManagement) DeclareQueue(ctx context.Context, specification *QueueSpecification) (IQueueInfo, error) {
|
||||||
return newAmqpQueue(a, queueName)
|
var amqpQueue *AmqpQueue
|
||||||
|
|
||||||
|
if specification == nil || len(specification.Name) <= 0 {
|
||||||
|
// If the specification is nil or the name is empty, then we create a new queue
|
||||||
|
// with a random name with generateNameWithDefaultPrefix()
|
||||||
|
amqpQueue = newAmqpQueue(a, "")
|
||||||
|
} else {
|
||||||
|
amqpQueue = newAmqpQueue(a, specification.Name)
|
||||||
|
amqpQueue.AutoDelete(specification.IsAutoDelete)
|
||||||
|
amqpQueue.Exclusive(specification.IsExclusive)
|
||||||
|
amqpQueue.MaxLengthBytes(specification.MaxLengthBytes)
|
||||||
|
amqpQueue.DeadLetterExchange(specification.DeadLetterExchange)
|
||||||
|
amqpQueue.DeadLetterRoutingKey(specification.DeadLetterRoutingKey)
|
||||||
|
amqpQueue.QueueType(specification.QueueType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return amqpQueue.Declare(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *AmqpManagement) DeleteQueue(ctx context.Context, name string) error {
|
||||||
|
q := newAmqpQueue(a, name)
|
||||||
|
return q.Delete(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AmqpManagement) DeclareExchange(ctx context.Context, exchangeSpecification *ExchangeSpecification) (IExchangeInfo, error) {
|
||||||
|
if exchangeSpecification == nil {
|
||||||
|
return nil, fmt.Errorf("exchangeSpecification is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
exchange := newAmqpExchange(a, exchangeSpecification.Name)
|
||||||
|
exchange.AutoDelete(exchangeSpecification.IsAutoDelete)
|
||||||
|
exchange.ExchangeType(exchangeSpecification.ExchangeType)
|
||||||
|
return exchange.Declare(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AmqpManagement) DeleteExchange(ctx context.Context, name string) error {
|
||||||
|
e := newAmqpExchange(a, name)
|
||||||
|
return e.Delete(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AmqpManagement) Bind(ctx context.Context, bindingSpecification *BindingSpecification) (string, error) {
|
||||||
|
bind := newAMQPBinding(a)
|
||||||
|
bind.SourceExchange(bindingSpecification.SourceExchange)
|
||||||
|
bind.DestinationQueue(bindingSpecification.DestinationQueue)
|
||||||
|
bind.DestinationExchange(bindingSpecification.DestinationExchange)
|
||||||
|
bind.BindingKey(bindingSpecification.BindingKey)
|
||||||
|
return bind.Bind(ctx)
|
||||||
|
|
||||||
|
}
|
||||||
|
func (a *AmqpManagement) Unbind(ctx context.Context, bindingPath string) error {
|
||||||
|
bind := newAMQPBinding(a)
|
||||||
|
return bind.Unbind(ctx, bindingPath)
|
||||||
|
}
|
||||||
func (a *AmqpManagement) QueueInfo(ctx context.Context, queueName string) (IQueueInfo, error) {
|
func (a *AmqpManagement) QueueInfo(ctx context.Context, queueName string) (IQueueInfo, error) {
|
||||||
path := queuePath(queueName)
|
path, err := NewAddressBuilder().Queue(queueName).Address()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
result, err := a.Request(ctx, amqp.Null{}, path, commandGet, []int{responseCode200, responseCode404})
|
result, err := a.Request(ctx, amqp.Null{}, path, commandGet, []int{responseCode200, responseCode404})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -214,14 +259,15 @@ func (a *AmqpManagement) QueueInfo(ctx context.Context, queueName string) (IQueu
|
||||||
return newAmqpQueueInfo(result), nil
|
return newAmqpQueueInfo(result), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpManagement) QueueClientName() IQueueSpecification {
|
func (a *AmqpManagement) PurgeQueue(ctx context.Context, queueName string) (int, error) {
|
||||||
return newAmqpQueue(a, "")
|
purge := newAmqpQueue(a, queueName)
|
||||||
|
return purge.Purge(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpManagement) NotifyStatusChange(channel chan *StatusChanged) {
|
func (a *AmqpManagement) NotifyStatusChange(channel chan *StatusChanged) {
|
||||||
a.lifeCycle.chStatusChanged = channel
|
a.lifeCycle.chStatusChanged = channel
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpManagement) GetStatus() int {
|
func (a *AmqpManagement) Status() int {
|
||||||
return a.lifeCycle.Status()
|
return a.lifeCycle.Status()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,13 @@ var _ = Describe("Management tests", func() {
|
||||||
cancel()
|
cancel()
|
||||||
err = amqpConnection.Management().Open(ctx, amqpConnection)
|
err = amqpConnection.Management().Open(ctx, amqpConnection)
|
||||||
Expect(err).NotTo(BeNil())
|
Expect(err).NotTo(BeNil())
|
||||||
amqpConnection.Close(context.Background())
|
Expect(amqpConnection.Close(context.Background())).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Management should receive events", func() {
|
It("AMQP Management should receive events", func() {
|
||||||
amqpConnection := NewAmqpConnection()
|
|
||||||
Expect(amqpConnection).NotTo(BeNil())
|
|
||||||
ch := make(chan *StatusChanged, 1)
|
ch := make(chan *StatusChanged, 1)
|
||||||
amqpConnection.Management().NotifyStatusChange(ch)
|
amqpConnection := NewAmqpConnectionNotifyStatusChanged(ch)
|
||||||
|
Expect(amqpConnection).NotTo(BeNil())
|
||||||
err := amqpConnection.Open(context.Background(), NewConnectionSettings())
|
err := amqpConnection.Open(context.Background(), NewConnectionSettings())
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
recv := <-ch
|
recv := <-ch
|
||||||
|
|
@ -42,7 +41,7 @@ var _ = Describe("Management tests", func() {
|
||||||
|
|
||||||
Expect(recv.From).To(Equal(Open))
|
Expect(recv.From).To(Equal(Open))
|
||||||
Expect(recv.To).To(Equal(Closed))
|
Expect(recv.To).To(Equal(Closed))
|
||||||
amqpConnection.Close(context.Background())
|
Expect(amqpConnection.Close(context.Background())).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Request", func() {
|
It("Request", func() {
|
||||||
|
|
@ -68,7 +67,7 @@ var _ = Describe("Management tests", func() {
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(result).NotTo(BeNil())
|
Expect(result).NotTo(BeNil())
|
||||||
Expect(management.Close(context.Background())).To(BeNil())
|
Expect(management.Close(context.Background())).To(BeNil())
|
||||||
amqpConnection.Close(context.Background())
|
Expect(amqpConnection.Close(context.Background())).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("GET on non-existing queue returns ErrDoesNotExist", func() {
|
It("GET on non-existing queue returns ErrDoesNotExist", func() {
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,17 @@ type AmqpQueueInfo struct {
|
||||||
isAutoDelete bool
|
isAutoDelete bool
|
||||||
isExclusive bool
|
isExclusive bool
|
||||||
leader string
|
leader string
|
||||||
replicas []string
|
members []string
|
||||||
arguments map[string]any
|
arguments map[string]any
|
||||||
queueType TQueueType
|
queueType TQueueType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueueInfo) GetLeader() string {
|
func (a *AmqpQueueInfo) Leader() string {
|
||||||
return a.leader
|
return a.leader
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueueInfo) GetReplicas() []string {
|
func (a *AmqpQueueInfo) Members() []string {
|
||||||
return a.replicas
|
return a.members
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAmqpQueueInfo(response map[string]any) IQueueInfo {
|
func newAmqpQueueInfo(response map[string]any) IQueueInfo {
|
||||||
|
|
@ -33,7 +33,7 @@ func newAmqpQueueInfo(response map[string]any) IQueueInfo {
|
||||||
isExclusive: response["exclusive"].(bool),
|
isExclusive: response["exclusive"].(bool),
|
||||||
queueType: TQueueType(response["type"].(string)),
|
queueType: TQueueType(response["type"].(string)),
|
||||||
leader: response["leader"].(string),
|
leader: response["leader"].(string),
|
||||||
replicas: response["replicas"].([]string),
|
members: response["replicas"].([]string),
|
||||||
arguments: response["arguments"].(map[string]any),
|
arguments: response["arguments"].(map[string]any),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -54,11 +54,11 @@ func (a *AmqpQueueInfo) Type() TQueueType {
|
||||||
return a.queueType
|
return a.queueType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueueInfo) GetName() string {
|
func (a *AmqpQueueInfo) Name() string {
|
||||||
return a.name
|
return a.name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueueInfo) GetArguments() map[string]any {
|
func (a *AmqpQueueInfo) Arguments() map[string]any {
|
||||||
return a.arguments
|
return a.arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,24 +70,28 @@ type AmqpQueue struct {
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueue) DeadLetterExchange(dlx string) IQueueSpecification {
|
func (a *AmqpQueue) DeadLetterExchange(dlx string) {
|
||||||
|
if len(dlx) != 0 {
|
||||||
a.arguments["x-dead-letter-exchange"] = dlx
|
a.arguments["x-dead-letter-exchange"] = dlx
|
||||||
return a
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueue) DeadLetterRoutingKey(dlrk string) IQueueSpecification {
|
func (a *AmqpQueue) DeadLetterRoutingKey(dlrk string) {
|
||||||
|
if len(dlrk) != 0 {
|
||||||
a.arguments["x-dead-letter-routing-key"] = dlrk
|
a.arguments["x-dead-letter-routing-key"] = dlrk
|
||||||
return a
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueue) MaxLengthBytes(length int64) IQueueSpecification {
|
func (a *AmqpQueue) MaxLengthBytes(length int64) {
|
||||||
|
if length != 0 {
|
||||||
a.arguments["max-length-bytes"] = length
|
a.arguments["max-length-bytes"] = length
|
||||||
return a
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueue) QueueType(queueType QueueType) IQueueSpecification {
|
func (a *AmqpQueue) QueueType(queueType QueueType) {
|
||||||
|
if len(queueType.String()) != 0 {
|
||||||
a.arguments["x-queue-type"] = queueType.String()
|
a.arguments["x-queue-type"] = queueType.String()
|
||||||
return a
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueue) GetQueueType() TQueueType {
|
func (a *AmqpQueue) GetQueueType() TQueueType {
|
||||||
|
|
@ -97,25 +101,23 @@ func (a *AmqpQueue) GetQueueType() TQueueType {
|
||||||
return TQueueType(a.arguments["x-queue-type"].(string))
|
return TQueueType(a.arguments["x-queue-type"].(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueue) Exclusive(isExclusive bool) IQueueSpecification {
|
func (a *AmqpQueue) Exclusive(isExclusive bool) {
|
||||||
a.isExclusive = isExclusive
|
a.isExclusive = isExclusive
|
||||||
return a
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueue) IsExclusive() bool {
|
func (a *AmqpQueue) IsExclusive() bool {
|
||||||
return a.isExclusive
|
return a.isExclusive
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueue) AutoDelete(isAutoDelete bool) IQueueSpecification {
|
func (a *AmqpQueue) AutoDelete(isAutoDelete bool) {
|
||||||
a.isAutoDelete = isAutoDelete
|
a.isAutoDelete = isAutoDelete
|
||||||
return a
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueue) IsAutoDelete() bool {
|
func (a *AmqpQueue) IsAutoDelete() bool {
|
||||||
return a.isAutoDelete
|
return a.isAutoDelete
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAmqpQueue(management *AmqpManagement, queueName string) IQueueSpecification {
|
func newAmqpQueue(management *AmqpManagement, queueName string) *AmqpQueue {
|
||||||
return &AmqpQueue{management: management,
|
return &AmqpQueue{management: management,
|
||||||
name: queueName,
|
name: queueName,
|
||||||
arguments: make(map[string]any)}
|
arguments: make(map[string]any)}
|
||||||
|
|
@ -135,7 +137,8 @@ func (a *AmqpQueue) Declare(ctx context.Context) (IQueueInfo, error) {
|
||||||
if Quorum == a.GetQueueType() ||
|
if Quorum == a.GetQueueType() ||
|
||||||
Stream == a.GetQueueType() {
|
Stream == a.GetQueueType() {
|
||||||
// mandatory arguments for quorum queues and streams
|
// mandatory arguments for quorum queues and streams
|
||||||
a.Exclusive(false).AutoDelete(false)
|
a.Exclusive(false)
|
||||||
|
a.AutoDelete(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.validate(); err != nil {
|
if err := a.validate(); err != nil {
|
||||||
|
|
@ -146,7 +149,10 @@ func (a *AmqpQueue) Declare(ctx context.Context) (IQueueInfo, error) {
|
||||||
a.name = generateNameWithDefaultPrefix()
|
a.name = generateNameWithDefaultPrefix()
|
||||||
}
|
}
|
||||||
|
|
||||||
path := queuePath(a.name)
|
path, err := NewAddressBuilder().Queue(a.name).Address()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
kv := make(map[string]any)
|
kv := make(map[string]any)
|
||||||
kv["durable"] = true
|
kv["durable"] = true
|
||||||
kv["auto_delete"] = a.isAutoDelete
|
kv["auto_delete"] = a.isAutoDelete
|
||||||
|
|
@ -160,22 +166,24 @@ func (a *AmqpQueue) Declare(ctx context.Context) (IQueueInfo, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueue) Delete(ctx context.Context) error {
|
func (a *AmqpQueue) Delete(ctx context.Context) error {
|
||||||
path := queuePath(a.name)
|
path, err := NewAddressBuilder().Queue(a.name).Address()
|
||||||
_, err := a.management.Request(ctx, amqp.Null{}, path, commandDelete, []int{responseCode200})
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = a.management.Request(ctx, amqp.Null{}, path, commandDelete, []int{responseCode200})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueue) Purge(ctx context.Context) (int, error) {
|
func (a *AmqpQueue) Purge(ctx context.Context) (int, error) {
|
||||||
path := queuePurgePath(a.name)
|
path, err := NewAddressBuilder().Queue(a.name).Append("/messages").Address()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
response, err := a.management.Request(ctx, amqp.Null{}, path, commandDelete, []int{responseCode200})
|
response, err := a.management.Request(ctx, amqp.Null{}, path, commandDelete, []int{responseCode200})
|
||||||
return int(response["message_count"].(uint64)), err
|
return int(response["message_count"].(uint64)), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueue) Name(queueName string) IQueueSpecification {
|
func (a *AmqpQueue) Name(queueName string) {
|
||||||
a.name = queueName
|
a.name = queueName
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AmqpQueue) GetName() string {
|
|
||||||
return a.name
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,12 @@ var _ = Describe("AMQP Queue test ", func() {
|
||||||
|
|
||||||
It("AMQP Queue Declare With Response and Get/Delete should succeed", func() {
|
It("AMQP Queue Declare With Response and Get/Delete should succeed", func() {
|
||||||
const queueName = "AMQP Queue Declare With Response and Delete should succeed"
|
const queueName = "AMQP Queue Declare With Response and Delete should succeed"
|
||||||
queueSpec := management.Queue(queueName)
|
queueInfo, err := management.DeclareQueue(context.TODO(), &QueueSpecification{
|
||||||
queueInfo, err := queueSpec.Declare(context.TODO())
|
Name: queueName,
|
||||||
|
})
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(queueInfo).NotTo(BeNil())
|
Expect(queueInfo).NotTo(BeNil())
|
||||||
Expect(queueInfo.GetName()).To(Equal(queueName))
|
Expect(queueInfo.Name()).To(Equal(queueName))
|
||||||
Expect(queueInfo.IsDurable()).To(BeTrue())
|
Expect(queueInfo.IsDurable()).To(BeTrue())
|
||||||
Expect(queueInfo.IsAutoDelete()).To(BeFalse())
|
Expect(queueInfo.IsAutoDelete()).To(BeFalse())
|
||||||
Expect(queueInfo.IsExclusive()).To(BeFalse())
|
Expect(queueInfo.IsExclusive()).To(BeFalse())
|
||||||
|
|
@ -45,137 +46,160 @@ var _ = Describe("AMQP Queue test ", func() {
|
||||||
queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName)
|
queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName)
|
||||||
Expect(queueInfoReceived).To(Equal(queueInfo))
|
Expect(queueInfoReceived).To(Equal(queueInfo))
|
||||||
|
|
||||||
err = queueSpec.Delete(context.TODO())
|
err = management.DeleteQueue(context.TODO(), queueName)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Queue Declare With Parameters and Get/Delete should succeed", func() {
|
It("AMQP Queue Declare With Parameters and Get/Delete should succeed", func() {
|
||||||
const queueName = "AMQP Queue Declare With Parameters and Delete should succeed"
|
const queueName = "AMQP Queue Declare With Parameters and Delete should succeed"
|
||||||
queueSpec := management.Queue(queueName).Exclusive(true).
|
|
||||||
AutoDelete(true).
|
queueInfo, err := management.DeclareQueue(context.TODO(), &QueueSpecification{
|
||||||
QueueType(QueueType{Classic}).
|
Name: queueName,
|
||||||
MaxLengthBytes(CapacityGB(1)).
|
IsAutoDelete: true,
|
||||||
DeadLetterExchange("dead-letter-exchange").
|
IsExclusive: true,
|
||||||
DeadLetterRoutingKey("dead-letter-routing-key")
|
QueueType: QueueType{Classic},
|
||||||
queueInfo, err := queueSpec.Declare(context.TODO())
|
MaxLengthBytes: CapacityGB(1),
|
||||||
|
DeadLetterExchange: "dead-letter-exchange",
|
||||||
|
DeadLetterRoutingKey: "dead-letter-routing-key",
|
||||||
|
})
|
||||||
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(queueInfo).NotTo(BeNil())
|
Expect(queueInfo).NotTo(BeNil())
|
||||||
Expect(queueInfo.GetName()).To(Equal(queueName))
|
Expect(queueInfo.Name()).To(Equal(queueName))
|
||||||
Expect(queueInfo.IsDurable()).To(BeTrue())
|
Expect(queueInfo.IsDurable()).To(BeTrue())
|
||||||
Expect(queueInfo.IsAutoDelete()).To(BeTrue())
|
Expect(queueInfo.IsAutoDelete()).To(BeTrue())
|
||||||
Expect(queueInfo.IsExclusive()).To(BeTrue())
|
Expect(queueInfo.IsExclusive()).To(BeTrue())
|
||||||
Expect(queueInfo.Type()).To(Equal(Classic))
|
Expect(queueInfo.Type()).To(Equal(Classic))
|
||||||
Expect(queueInfo.GetLeader()).To(ContainSubstring("rabbit"))
|
Expect(queueInfo.Leader()).To(ContainSubstring("rabbit"))
|
||||||
Expect(len(queueInfo.GetReplicas())).To(BeNumerically(">", 0))
|
Expect(len(queueInfo.Members())).To(BeNumerically(">", 0))
|
||||||
|
|
||||||
Expect(queueInfo.GetArguments()).To(HaveKeyWithValue("x-dead-letter-exchange", "dead-letter-exchange"))
|
Expect(queueInfo.Arguments()).To(HaveKeyWithValue("x-dead-letter-exchange", "dead-letter-exchange"))
|
||||||
Expect(queueInfo.GetArguments()).To(HaveKeyWithValue("x-dead-letter-routing-key", "dead-letter-routing-key"))
|
Expect(queueInfo.Arguments()).To(HaveKeyWithValue("x-dead-letter-routing-key", "dead-letter-routing-key"))
|
||||||
Expect(queueInfo.GetArguments()).To(HaveKeyWithValue("max-length-bytes", int64(1000000000)))
|
Expect(queueInfo.Arguments()).To(HaveKeyWithValue("max-length-bytes", int64(1000000000)))
|
||||||
|
|
||||||
// validate GET (query queue info)
|
// validate GET (query queue info)
|
||||||
queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName)
|
queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName)
|
||||||
Expect(queueInfoReceived).To(Equal(queueInfo))
|
Expect(queueInfoReceived).To(Equal(queueInfo))
|
||||||
|
|
||||||
err = queueSpec.Delete(context.TODO())
|
err = management.DeleteQueue(context.TODO(), queueName)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Declare Quorum Queue and Get/Delete should succeed", func() {
|
It("AMQP Declare Quorum Queue and Get/Delete should succeed", func() {
|
||||||
const queueName = "AMQP Declare Quorum Queue and Delete should succeed"
|
const queueName = "AMQP Declare Quorum Queue and Delete should succeed"
|
||||||
// Quorum queue will ignore Exclusive and AutoDelete settings
|
// Quorum queue will ignore Exclusive and AutoDelete settings
|
||||||
// since they are not supported by quorum queues
|
// since they are not supported by quorum queues
|
||||||
queueSpec := management.Queue(queueName).
|
queueInfo, err := management.DeclareQueue(context.TODO(), &QueueSpecification{
|
||||||
Exclusive(true).
|
Name: queueName,
|
||||||
AutoDelete(true).QueueType(QueueType{Quorum})
|
IsAutoDelete: true,
|
||||||
queueInfo, err := queueSpec.Declare(context.TODO())
|
IsExclusive: true,
|
||||||
|
QueueType: QueueType{Quorum},
|
||||||
|
})
|
||||||
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(queueInfo).NotTo(BeNil())
|
Expect(queueInfo).NotTo(BeNil())
|
||||||
Expect(queueInfo.GetName()).To(Equal(queueName))
|
Expect(queueInfo.Name()).To(Equal(queueName))
|
||||||
Expect(queueInfo.IsDurable()).To(BeTrue())
|
Expect(queueInfo.IsDurable()).To(BeTrue())
|
||||||
Expect(queueInfo.IsAutoDelete()).To(BeFalse())
|
Expect(queueInfo.IsAutoDelete()).To(BeFalse())
|
||||||
Expect(queueInfo.IsExclusive()).To(BeFalse())
|
Expect(queueInfo.IsExclusive()).To(BeFalse())
|
||||||
Expect(queueInfo.Type()).To(Equal(Quorum))
|
Expect(queueInfo.Type()).To(Equal(Quorum))
|
||||||
|
|
||||||
// validate GET (query queue info)
|
// validate GET (query queue info)
|
||||||
queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName)
|
queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName)
|
||||||
Expect(queueInfoReceived).To(Equal(queueInfo))
|
Expect(queueInfoReceived).To(Equal(queueInfo))
|
||||||
|
|
||||||
err = queueSpec.Delete(context.TODO())
|
err = management.DeleteQueue(context.TODO(), queueName)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Declare Stream Queue and Get/Delete should succeed", func() {
|
It("AMQP Declare Stream Queue and Get/Delete should succeed", func() {
|
||||||
const queueName = "AMQP Declare Stream Queue and Delete should succeed"
|
const queueName = "AMQP Declare Stream Queue and Delete should succeed"
|
||||||
// Stream queue will ignore Exclusive and AutoDelete settings
|
// Stream queue will ignore Exclusive and AutoDelete settings
|
||||||
// since they are not supported by quorum queues
|
// since they are not supported by quorum queues
|
||||||
queueSpec := management.Queue(queueName).
|
|
||||||
Exclusive(true).
|
queueInfo, err := management.DeclareQueue(context.TODO(), &QueueSpecification{
|
||||||
AutoDelete(true).QueueType(QueueType{Stream})
|
Name: queueName,
|
||||||
queueInfo, err := queueSpec.Declare(context.TODO())
|
IsAutoDelete: true,
|
||||||
|
IsExclusive: true,
|
||||||
|
QueueType: QueueType{Stream},
|
||||||
|
})
|
||||||
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(queueInfo).NotTo(BeNil())
|
Expect(queueInfo).NotTo(BeNil())
|
||||||
Expect(queueInfo.GetName()).To(Equal(queueName))
|
Expect(queueInfo.Name()).To(Equal(queueName))
|
||||||
Expect(queueInfo.IsDurable()).To(BeTrue())
|
Expect(queueInfo.IsDurable()).To(BeTrue())
|
||||||
Expect(queueInfo.IsAutoDelete()).To(BeFalse())
|
Expect(queueInfo.IsAutoDelete()).To(BeFalse())
|
||||||
Expect(queueInfo.IsExclusive()).To(BeFalse())
|
Expect(queueInfo.IsExclusive()).To(BeFalse())
|
||||||
Expect(queueInfo.Type()).To(Equal(Stream))
|
Expect(queueInfo.Type()).To(Equal(Stream))
|
||||||
|
|
||||||
// validate GET (query queue info)
|
// validate GET (query queue info)
|
||||||
queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName)
|
queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName)
|
||||||
Expect(queueInfoReceived).To(Equal(queueInfo))
|
Expect(queueInfoReceived).To(Equal(queueInfo))
|
||||||
|
|
||||||
err = queueSpec.Delete(context.TODO())
|
err = management.DeleteQueue(context.TODO(), queueName)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Declare Queue with invalid type should fail", func() {
|
It("AMQP Declare Queue with invalid type should fail", func() {
|
||||||
const queueName = "AMQP Declare Queue with invalid type should fail"
|
const queueName = "AMQP Declare Queue with invalid type should fail"
|
||||||
queueSpec := management.Queue(queueName).
|
_, err := management.DeclareQueue(context.TODO(), &QueueSpecification{
|
||||||
QueueType(QueueType{Type: "invalid"})
|
Name: queueName,
|
||||||
_, err := queueSpec.Declare(context.TODO())
|
QueueType: QueueType{Type: "invalid"},
|
||||||
|
})
|
||||||
Expect(err).NotTo(BeNil())
|
Expect(err).NotTo(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Declare Queue should fail with Precondition fail", func() {
|
It("AMQP Declare Queue should fail with Precondition fail", func() {
|
||||||
// The first queue is declared as Classic and it should succeed
|
// The first queue is declared as Classic, and it should succeed
|
||||||
// The second queue is declared as Quorum and it should fail since it is already declared as Classic
|
// The second queue is declared as Quorum, and it should fail since it is already declared as Classic
|
||||||
const queueName = "AMQP Declare Queue should fail with Precondition fail"
|
const queueName = "AMQP Declare Queue should fail with Precondition fail"
|
||||||
queueSpec := management.Queue(queueName).QueueType(QueueType{Classic})
|
|
||||||
_, err := queueSpec.Declare(context.TODO())
|
_, err := management.DeclareQueue(context.TODO(), &QueueSpecification{
|
||||||
|
Name: queueName,
|
||||||
|
QueueType: QueueType{Classic},
|
||||||
|
})
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
queueSpecFail := management.Queue(queueName).QueueType(QueueType{Quorum})
|
|
||||||
_, err = queueSpecFail.Declare(context.TODO())
|
_, err = management.DeclareQueue(context.TODO(), &QueueSpecification{
|
||||||
|
Name: queueName,
|
||||||
|
QueueType: QueueType{Quorum},
|
||||||
|
})
|
||||||
|
|
||||||
Expect(err).NotTo(BeNil())
|
Expect(err).NotTo(BeNil())
|
||||||
Expect(err).To(Equal(ErrPreconditionFailed))
|
Expect(err).To(Equal(ErrPreconditionFailed))
|
||||||
err = queueSpec.Delete(context.TODO())
|
err = management.DeleteQueue(context.TODO(), queueName)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Declare Queue should fail during validation", func() {
|
It("AMQP Declare Queue should fail during validation", func() {
|
||||||
const queueName = "AMQP Declare Queue should fail during validation"
|
const queueName = "AMQP Declare Queue should fail during validation"
|
||||||
queueSpec := management.Queue(queueName).MaxLengthBytes(-1)
|
_, err := management.DeclareQueue(context.TODO(), &QueueSpecification{
|
||||||
_, err := queueSpec.Declare(context.TODO())
|
Name: queueName,
|
||||||
|
MaxLengthBytes: -1,
|
||||||
|
})
|
||||||
|
|
||||||
Expect(err).NotTo(BeNil())
|
Expect(err).NotTo(BeNil())
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Declare Queue should create client name queue", func() {
|
It("AMQP Declare Queue should create client name queue", func() {
|
||||||
queueSpec := management.QueueClientName()
|
queueInfo, err := management.DeclareQueue(context.TODO(), nil)
|
||||||
queueInfo, err := queueSpec.Declare(context.TODO())
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(queueInfo).NotTo(BeNil())
|
Expect(queueInfo).NotTo(BeNil())
|
||||||
Expect(queueInfo.GetName()).To(ContainSubstring("client.gen-"))
|
Expect(queueInfo.Name()).To(ContainSubstring("client.gen-"))
|
||||||
err = queueSpec.Delete(context.TODO())
|
err = management.DeleteQueue(context.TODO(), queueInfo.Name())
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Purge Queue should succeed and return the number of messages purged", func() {
|
It("AMQP Purge Queue should succeed and return the number of messages purged", func() {
|
||||||
const queueName = "AMQP Purge Queue should succeed and return the number of messages purged"
|
const queueName = "AMQP Purge Queue should succeed and return the number of messages purged"
|
||||||
queueSpec := management.Queue(queueName)
|
queueInfo, err := management.DeclareQueue(context.TODO(), &QueueSpecification{
|
||||||
_, err := queueSpec.Declare(context.TODO())
|
Name: queueName,
|
||||||
|
})
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
publishMessages(queueName, 10)
|
publishMessages(queueName, 10)
|
||||||
purged, err := queueSpec.Purge(context.TODO())
|
purged, err := management.PurgeQueue(context.TODO(), queueInfo.Name())
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(purged).To(Equal(10))
|
Expect(purged).To(Equal(10))
|
||||||
})
|
})
|
||||||
|
|
@ -199,7 +223,13 @@ func publishMessages(queueName string, count int) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fail(err.Error())
|
Fail(err.Error())
|
||||||
}
|
}
|
||||||
sender, err := session.NewSender(context.TODO(), queuePath(queueName), nil)
|
|
||||||
|
address, err := NewAddressBuilder().Queue(queueName).Address()
|
||||||
|
if err != nil {
|
||||||
|
Fail(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
sender, err := session.NewSender(context.TODO(), address, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fail(err.Error())
|
Fail(err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,8 @@ import (
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -29,73 +27,6 @@ const (
|
||||||
bindings = "bindings"
|
bindings = "bindings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// encodePathSegments takes a string and returns its percent-encoded representation.
|
|
||||||
func encodePathSegments(input string) string {
|
|
||||||
var encoded strings.Builder
|
|
||||||
|
|
||||||
// Iterate over each character in the input string
|
|
||||||
for _, char := range input {
|
|
||||||
// Check if the character is an unreserved character (i.e., it doesn't need encoding)
|
|
||||||
if isUnreserved(char) {
|
|
||||||
encoded.WriteRune(char) // Append as is
|
|
||||||
} else {
|
|
||||||
// Encode character To %HH format
|
|
||||||
encoded.WriteString(fmt.Sprintf("%%%02X", char))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return encoded.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode takes a percent-encoded string and returns its decoded representation.
|
|
||||||
func decode(input string) (string, error) {
|
|
||||||
// Use url.QueryUnescape which properly decodes percent-encoded strings
|
|
||||||
decoded, err := url.QueryUnescape(input)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return decoded, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// isUnreserved checks if a character is an unreserved character in percent encoding
|
|
||||||
// Unreserved characters are: A-Z, a-z, 0-9, -, ., _, ~
|
|
||||||
func isUnreserved(char rune) bool {
|
|
||||||
return (char >= 'A' && char <= 'Z') ||
|
|
||||||
(char >= 'a' && char <= 'z') ||
|
|
||||||
(char >= '0' && char <= '9') ||
|
|
||||||
char == '-' || char == '.' || char == '_' || char == '~'
|
|
||||||
}
|
|
||||||
|
|
||||||
func queuePath(queueName string) string {
|
|
||||||
return "/" + queues + "/" + encodePathSegments(queueName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func queuePurgePath(queueName string) string {
|
|
||||||
return "/" + queues + "/" + encodePathSegments(queueName) + "/messages"
|
|
||||||
}
|
|
||||||
|
|
||||||
func exchangePath(exchangeName string) string {
|
|
||||||
return "/" + exchanges + "/" + encodePathSegments(exchangeName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func bindingPath() string {
|
|
||||||
return "/" + bindings
|
|
||||||
}
|
|
||||||
|
|
||||||
func bindingPathWithExchangeQueueKey(toQueue bool, sourceName, destinationName, key string) string {
|
|
||||||
sourceNameEncoded := encodePathSegments(sourceName)
|
|
||||||
destinationNameEncoded := encodePathSegments(destinationName)
|
|
||||||
keyEncoded := encodePathSegments(key)
|
|
||||||
destinationType := "dste"
|
|
||||||
if toQueue {
|
|
||||||
destinationType = "dstq"
|
|
||||||
}
|
|
||||||
format := "/%s/src=%s;%s=%s;key=%s;args="
|
|
||||||
return fmt.Sprintf(format, bindings, sourceNameEncoded, destinationType, destinationNameEncoded, keyEncoded)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func validatePositive(label string, value int64) error {
|
func validatePositive(label string, value int64) error {
|
||||||
if value < 0 {
|
if value < 0 {
|
||||||
return fmt.Errorf("value for %s must be positive, got %d", label, value)
|
return fmt.Errorf("value for %s must be positive, got %d", label, value)
|
||||||
|
|
@ -119,3 +50,8 @@ func generateName(prefix string) string {
|
||||||
result = strings.ReplaceAll(result, "=", "")
|
result = strings.ReplaceAll(result, "=", "")
|
||||||
return prefix + result
|
return prefix + result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isStringNilOrEmpty(str *string) bool {
|
||||||
|
return str == nil || len(*str) == 0
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package rabbitmq_amqp
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TSaslMechanism string
|
type TSaslMechanism string
|
||||||
|
|
@ -17,33 +18,52 @@ type SaslMechanism struct {
|
||||||
Type TSaslMechanism
|
Type TSaslMechanism
|
||||||
}
|
}
|
||||||
|
|
||||||
type IConnectionSettings interface {
|
type ConnectionSettings struct {
|
||||||
GetHost() string
|
Host string
|
||||||
Host(hostName string) IConnectionSettings
|
Port int
|
||||||
GetPort() int
|
User string
|
||||||
Port(port int) IConnectionSettings
|
Password string
|
||||||
GetUser() string
|
VirtualHost string
|
||||||
User(userName string) IConnectionSettings
|
Scheme string
|
||||||
GetPassword() string
|
ContainerId string
|
||||||
Password(password string) IConnectionSettings
|
UseSsl bool
|
||||||
GetVirtualHost() string
|
TlsConfig *tls.Config
|
||||||
VirtualHost(virtualHost string) IConnectionSettings
|
SaslMechanism TSaslMechanism
|
||||||
GetScheme() string
|
}
|
||||||
GetContainerId() string
|
|
||||||
ContainerId(containerId string) IConnectionSettings
|
func (c *ConnectionSettings) BuildAddress() string {
|
||||||
UseSsl(value bool) IConnectionSettings
|
return c.Scheme + "://" + c.Host + ":" + fmt.Sprint(c.Port)
|
||||||
IsSsl() bool
|
}
|
||||||
BuildAddress() string
|
|
||||||
TlsConfig(config *tls.Config) IConnectionSettings
|
// NewConnectionSettings creates a new ConnectionSettings struct with default values.
|
||||||
GetTlsConfig() *tls.Config
|
func NewConnectionSettings() *ConnectionSettings {
|
||||||
GetSaslMechanism() TSaslMechanism
|
return &ConnectionSettings{
|
||||||
SaslMechanism(mechanism SaslMechanism) IConnectionSettings
|
Host: "localhost",
|
||||||
|
Port: 5672,
|
||||||
|
User: "guest",
|
||||||
|
Password: "guest",
|
||||||
|
VirtualHost: "/",
|
||||||
|
Scheme: "amqp",
|
||||||
|
ContainerId: "amqp-go-client",
|
||||||
|
UseSsl: false,
|
||||||
|
TlsConfig: nil,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type IConnection interface {
|
type IConnection interface {
|
||||||
Open(ctx context.Context, connectionSettings IConnectionSettings) error
|
// Open opens a connection to the AMQP 1.0 server.
|
||||||
|
Open(ctx context.Context, connectionSettings *ConnectionSettings) error
|
||||||
|
|
||||||
|
// Close closes the connection to the AMQP 1.0 server.
|
||||||
Close(ctx context.Context) error
|
Close(ctx context.Context) error
|
||||||
|
|
||||||
|
// Management returns the management interface for the connection.
|
||||||
Management() IManagement
|
Management() IManagement
|
||||||
|
|
||||||
|
// NotifyStatusChange registers a channel to receive status change notifications.
|
||||||
|
// The channel will receive a StatusChanged struct whenever the status of the connection changes.
|
||||||
NotifyStatusChange(channel chan *StatusChanged)
|
NotifyStatusChange(channel chan *StatusChanged)
|
||||||
GetStatus() int
|
// Status returns the current status of the connection.
|
||||||
|
// See LifeCycle struct for more information.
|
||||||
|
Status() int
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ func CapacityFrom(value string) (int64, error) {
|
||||||
match, err := regexp.Compile("^((kb|mb|gb|tb))")
|
match, err := regexp.Compile("^((kb|mb|gb|tb))")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0,
|
return 0,
|
||||||
fmt.Errorf("Capacity, invalid unit size format:%s", value)
|
fmt.Errorf("capacity, invalid unit size format:%s", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
foundUnitSize := strings.ToLower(value[len(value)-2:])
|
foundUnitSize := strings.ToLower(value[len(value)-2:])
|
||||||
|
|
@ -55,7 +55,7 @@ func CapacityFrom(value string) (int64, error) {
|
||||||
|
|
||||||
size, err := strconv.Atoi(value[:len(value)-2])
|
size, err := strconv.Atoi(value[:len(value)-2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("Capacity, Invalid number format: %s", value)
|
return 0, fmt.Errorf("capacity, Invalid number format: %s", value)
|
||||||
}
|
}
|
||||||
switch foundUnitSize {
|
switch foundUnitSize {
|
||||||
case UnitKb:
|
case UnitKb:
|
||||||
|
|
@ -72,5 +72,5 @@ func CapacityFrom(value string) (int64, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, fmt.Errorf("Capacity, Invalid unit size format: %s", value)
|
return 0, fmt.Errorf("capacity, Invalid unit size format: %s", value)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,5 @@
|
||||||
package rabbitmq_amqp
|
package rabbitmq_amqp
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TQueueType string
|
type TQueueType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -20,38 +16,29 @@ func (e QueueType) String() string {
|
||||||
return string(e.Type)
|
return string(e.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
type IEntityInfoSpecification[T any] interface {
|
// QueueSpecification represents the specification of a queue
|
||||||
Declare(ctx context.Context) (T, error)
|
type QueueSpecification struct {
|
||||||
Delete(ctx context.Context) error
|
Name string
|
||||||
}
|
IsAutoDelete bool
|
||||||
|
IsExclusive bool
|
||||||
type IQueueSpecification interface {
|
QueueType QueueType
|
||||||
GetName() string
|
MaxLengthBytes int64
|
||||||
Exclusive(isExclusive bool) IQueueSpecification
|
DeadLetterExchange string
|
||||||
IsExclusive() bool
|
DeadLetterRoutingKey string
|
||||||
AutoDelete(isAutoDelete bool) IQueueSpecification
|
|
||||||
IsAutoDelete() bool
|
|
||||||
IEntityInfoSpecification[IQueueInfo]
|
|
||||||
QueueType(queueType QueueType) IQueueSpecification
|
|
||||||
GetQueueType() TQueueType
|
|
||||||
MaxLengthBytes(length int64) IQueueSpecification
|
|
||||||
DeadLetterExchange(dlx string) IQueueSpecification
|
|
||||||
DeadLetterRoutingKey(dlrk string) IQueueSpecification
|
|
||||||
Purge(ctx context.Context) (int, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IQueueInfo represents the information of a queue
|
// IQueueInfo represents the information of a queue
|
||||||
// It is returned by the Declare method of IQueueSpecification
|
// It is returned by the Declare method of IQueueSpecification
|
||||||
// The information come from the server
|
// The information come from the server
|
||||||
type IQueueInfo interface {
|
type IQueueInfo interface {
|
||||||
GetName() string
|
Name() string
|
||||||
IsDurable() bool
|
IsDurable() bool
|
||||||
IsAutoDelete() bool
|
IsAutoDelete() bool
|
||||||
IsExclusive() bool
|
IsExclusive() bool
|
||||||
Type() TQueueType
|
Type() TQueueType
|
||||||
GetLeader() string
|
Leader() string
|
||||||
GetReplicas() []string
|
Members() []string
|
||||||
GetArguments() map[string]any
|
Arguments() map[string]any
|
||||||
}
|
}
|
||||||
|
|
||||||
type TExchangeType string
|
type TExchangeType string
|
||||||
|
|
@ -74,24 +61,18 @@ func (e ExchangeType) String() string {
|
||||||
// It is empty at the moment because the server does not return any information
|
// It is empty at the moment because the server does not return any information
|
||||||
// We leave it here for future use. In case the server returns information about an exchange
|
// We leave it here for future use. In case the server returns information about an exchange
|
||||||
type IExchangeInfo interface {
|
type IExchangeInfo interface {
|
||||||
GetName() string
|
Name() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type IExchangeSpecification interface {
|
type ExchangeSpecification struct {
|
||||||
GetName() string
|
Name string
|
||||||
AutoDelete(isAutoDelete bool) IExchangeSpecification
|
IsAutoDelete bool
|
||||||
IsAutoDelete() bool
|
ExchangeType ExchangeType
|
||||||
IEntityInfoSpecification[IExchangeInfo]
|
|
||||||
ExchangeType(exchangeType ExchangeType) IExchangeSpecification
|
|
||||||
GetExchangeType() TExchangeType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type IBindingSpecification interface {
|
type BindingSpecification struct {
|
||||||
SourceExchange(exchangeSpec IExchangeSpecification) IBindingSpecification
|
SourceExchange string
|
||||||
SourceExchangeName(exchangeName string) IBindingSpecification
|
DestinationQueue string
|
||||||
DestinationQueue(queueSpec IQueueSpecification) IBindingSpecification
|
DestinationExchange string
|
||||||
DestinationQueueName(queueName string) IBindingSpecification
|
BindingKey string
|
||||||
Key(bindingKey string) IBindingSpecification
|
|
||||||
Bind(ctx context.Context) error
|
|
||||||
Unbind(ctx context.Context) error
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
package rabbitmq_amqp
|
package rabbitmq_amqp
|
||||||
|
|
||||||
import "sync"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Open = iota
|
Open = iota
|
||||||
|
|
@ -9,11 +12,30 @@ const (
|
||||||
Closed = iota
|
Closed = iota
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func statusToString(status int) string {
|
||||||
|
switch status {
|
||||||
|
case Open:
|
||||||
|
return "Open"
|
||||||
|
case Reconnecting:
|
||||||
|
return "Reconnecting"
|
||||||
|
case Closing:
|
||||||
|
return "Closing"
|
||||||
|
case Closed:
|
||||||
|
return "Closed"
|
||||||
|
}
|
||||||
|
return "Unknown"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
type StatusChanged struct {
|
type StatusChanged struct {
|
||||||
From int
|
From int
|
||||||
To int
|
To int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s StatusChanged) String() string {
|
||||||
|
return fmt.Sprintf("From: %s, To: %s", statusToString(s.From), statusToString(s.To))
|
||||||
|
}
|
||||||
|
|
||||||
type LifeCycle struct {
|
type LifeCycle struct {
|
||||||
status int
|
status int
|
||||||
chStatusChanged chan *StatusChanged
|
chStatusChanged chan *StatusChanged
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,40 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type IManagement interface {
|
type IManagement interface {
|
||||||
|
// Open setups the sender and receiver links to the management interface.
|
||||||
Open(ctx context.Context, connection IConnection) error
|
Open(ctx context.Context, connection IConnection) error
|
||||||
|
// Close closes the sender and receiver links to the management interface.
|
||||||
Close(ctx context.Context) error
|
Close(ctx context.Context) error
|
||||||
Queue(queueName string) IQueueSpecification
|
|
||||||
|
// DeclareQueue creates a queue with the specified specification.
|
||||||
|
DeclareQueue(ctx context.Context, specification *QueueSpecification) (IQueueInfo, error)
|
||||||
|
// DeleteQueue deletes the queue with the specified name.
|
||||||
|
DeleteQueue(ctx context.Context, name string) error
|
||||||
|
// DeclareExchange creates an exchange with the specified specification.
|
||||||
|
DeclareExchange(ctx context.Context, exchangeSpecification *ExchangeSpecification) (IExchangeInfo, error)
|
||||||
|
// DeleteExchange deletes the exchange with the specified name.
|
||||||
|
DeleteExchange(ctx context.Context, name string) error
|
||||||
|
//Bind creates a binding between an exchange and a queue or exchange
|
||||||
|
Bind(ctx context.Context, bindingSpecification *BindingSpecification) (string, error)
|
||||||
|
// Unbind removes a binding between an exchange and a queue or exchange given the binding path.
|
||||||
|
Unbind(ctx context.Context, bindingPath string) error
|
||||||
|
// PurgeQueue removes all messages from the queue. Returns the number of messages purged.
|
||||||
|
PurgeQueue(ctx context.Context, queueName string) (int, error)
|
||||||
|
// QueueInfo returns information about the queue with the specified name.
|
||||||
QueueInfo(ctx context.Context, queueName string) (IQueueInfo, error)
|
QueueInfo(ctx context.Context, queueName string) (IQueueInfo, error)
|
||||||
Exchange(exchangeName string) IExchangeSpecification
|
|
||||||
Binding() IBindingSpecification
|
// Status returns the current status of the management interface.
|
||||||
QueueClientName() IQueueSpecification
|
// See LifeCycle struct for more information.
|
||||||
GetStatus() int
|
Status() int
|
||||||
|
|
||||||
|
// NotifyStatusChange registers a channel to receive status change notifications.
|
||||||
|
// The channel will receive a StatusChanged struct whenever the status of the management interface changes.
|
||||||
NotifyStatusChange(channel chan *StatusChanged)
|
NotifyStatusChange(channel chan *StatusChanged)
|
||||||
|
|
||||||
|
//Request sends a request to the management interface with the specified body, path, and method.
|
||||||
|
//Returns the response body as a map[string]any.
|
||||||
|
//It usually is not necessary to call this method directly. Leave it public for custom use cases.
|
||||||
|
// The calls above are the recommended way to interact with the management interface.
|
||||||
Request(ctx context.Context, body any, path string, method string,
|
Request(ctx context.Context, body any, path string, method string,
|
||||||
expectedResponseCodes []int) (map[string]any, error)
|
expectedResponseCodes []int) (map[string]any, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue