From df42cff33a06917e73297c83c07f2ba0ce20c7ed Mon Sep 17 00:00:00 2001 From: WiRight Date: Mon, 24 Apr 2023 09:46:05 +0300 Subject: [PATCH 01/12] rename to github.com/DizoftTeam/go-rabbitmq --- README.md | 4 +- connection.go | 2 +- consume.go | 2 +- consumer_options.go | 2 +- declare.go | 2 +- examples/consumer/main.go | 2 +- examples/logger/main.go | 2 +- examples/multiconsumer/main.go | 2 +- examples/multipublisher/main.go | 2 +- examples/publisher/main.go | 2 +- go.mod | 4 +- go.sum | 34 ++------------ internal/channelmanager/channel_manager.go | 6 +-- .../connectionmanager/connection_manager.go | 4 +- logger.go | 2 +- publish.go | 4 +- .../rabbitmq/amqp091-go/CHANGELOG.md | 18 +++++++ .../rabbitmq/amqp091-go/CONTRIBUTING.md | 18 ++++++- .../github.com/rabbitmq/amqp091-go/Makefile | 5 ++ .../github.com/rabbitmq/amqp091-go/channel.go | 14 ++++-- .../rabbitmq/amqp091-go/confirms.go | 23 ++++++++- .../rabbitmq/amqp091-go/connection.go | 47 +++++++++++++++++++ .../rabbitmq/amqp091-go/consumers.go | 27 +++++++++++ .../github.com/rabbitmq/amqp091-go/types.go | 5 ++ vendor/modules.txt | 2 +- 25 files changed, 175 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 00e9ce9..cddec6e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Wrapper of [rabbitmq/amqp091-go](https://github.com/rabbitmq/amqp091-go) that pr Supported by [Boot.dev](https://boot.dev) -[![](https://godoc.org/github.com/wagslane/go-rabbitmq?status.svg)](https://godoc.org/github.com/wagslane/go-rabbitmq)![Deploy](https://github.com/wagslane/go-rabbitmq/workflows/Tests/badge.svg) +[![](https://godoc.org/github.com/DizoftTeam/go-rabbitmq?status.svg)](https://godoc.org/github.com/DizoftTeam/go-rabbitmq)![Deploy](https://github.com/DizoftTeam/go-rabbitmq/workflows/Tests/badge.svg) ## Motivation @@ -25,7 +25,7 @@ The goal with `go-rabbitmq` is to provide *most* (but not all) of the nitty-grit Inside a Go module: ```bash -go get github.com/wagslane/go-rabbitmq +go get github.com/DizoftTeam/go-rabbitmq ``` ## 🚀 Quick Start Consumer diff --git a/connection.go b/connection.go index 97b8bb4..32a81a8 100644 --- a/connection.go +++ b/connection.go @@ -1,8 +1,8 @@ package rabbitmq import ( + "github.com/DizoftTeam/go-rabbitmq/internal/connectionmanager" amqp "github.com/rabbitmq/amqp091-go" - "github.com/wagslane/go-rabbitmq/internal/connectionmanager" ) // Conn manages the connection to a rabbit cluster diff --git a/consume.go b/consume.go index d1f802f..b3b682f 100644 --- a/consume.go +++ b/consume.go @@ -5,8 +5,8 @@ import ( "fmt" "sync" + "github.com/DizoftTeam/go-rabbitmq/internal/channelmanager" amqp "github.com/rabbitmq/amqp091-go" - "github.com/wagslane/go-rabbitmq/internal/channelmanager" ) // Action is an action that occurs after processed this delivery diff --git a/consumer_options.go b/consumer_options.go index 80f2979..5b7a313 100644 --- a/consumer_options.go +++ b/consumer_options.go @@ -1,8 +1,8 @@ package rabbitmq import ( + "github.com/DizoftTeam/go-rabbitmq/internal/logger" amqp "github.com/rabbitmq/amqp091-go" - "github.com/wagslane/go-rabbitmq/internal/logger" ) // getDefaultConsumerOptions describes the options that will be used when a value isn't provided diff --git a/declare.go b/declare.go index 86abe85..7379d4c 100644 --- a/declare.go +++ b/declare.go @@ -1,7 +1,7 @@ package rabbitmq import ( - "github.com/wagslane/go-rabbitmq/internal/channelmanager" + "github.com/DizoftTeam/go-rabbitmq/internal/channelmanager" ) func declareQueue(chanManager *channelmanager.ChannelManager, options QueueOptions) error { diff --git a/examples/consumer/main.go b/examples/consumer/main.go index 7c68733..2a7ed75 100644 --- a/examples/consumer/main.go +++ b/examples/consumer/main.go @@ -7,7 +7,7 @@ import ( "os/signal" "syscall" - rabbitmq "github.com/wagslane/go-rabbitmq" + rabbitmq "github.com/DizoftTeam/go-rabbitmq" ) func main() { diff --git a/examples/logger/main.go b/examples/logger/main.go index 8620e4c..ecb31c5 100644 --- a/examples/logger/main.go +++ b/examples/logger/main.go @@ -4,7 +4,7 @@ import ( "context" "log" - rabbitmq "github.com/wagslane/go-rabbitmq" + rabbitmq "github.com/DizoftTeam/go-rabbitmq" ) // errorLogger is used in WithPublisherOptionsLogger to create a custom logger diff --git a/examples/multiconsumer/main.go b/examples/multiconsumer/main.go index 571af8b..e481052 100644 --- a/examples/multiconsumer/main.go +++ b/examples/multiconsumer/main.go @@ -7,7 +7,7 @@ import ( "os/signal" "syscall" - rabbitmq "github.com/wagslane/go-rabbitmq" + rabbitmq "github.com/DizoftTeam/go-rabbitmq" ) func main() { diff --git a/examples/multipublisher/main.go b/examples/multipublisher/main.go index 5121a3f..12d966d 100644 --- a/examples/multipublisher/main.go +++ b/examples/multipublisher/main.go @@ -9,7 +9,7 @@ import ( "syscall" "time" - rabbitmq "github.com/wagslane/go-rabbitmq" + rabbitmq "github.com/DizoftTeam/go-rabbitmq" ) func main() { diff --git a/examples/publisher/main.go b/examples/publisher/main.go index d07cc27..b871640 100644 --- a/examples/publisher/main.go +++ b/examples/publisher/main.go @@ -9,7 +9,7 @@ import ( "syscall" "time" - rabbitmq "github.com/wagslane/go-rabbitmq" + rabbitmq "github.com/DizoftTeam/go-rabbitmq" ) func main() { diff --git a/go.mod b/go.mod index 3c21622..3aba60f 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,5 @@ -module github.com/wagslane/go-rabbitmq +module github.com/DizoftTeam/go-rabbitmq go 1.20 -require github.com/rabbitmq/amqp091-go v1.7.0 +require github.com/rabbitmq/amqp091-go v1.8.0 diff --git a/go.sum b/go.sum index e627709..787640a 100644 --- a/go.sum +++ b/go.sum @@ -4,40 +4,14 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rabbitmq/amqp091-go v1.7.0 h1:V5CF5qPem5OGSnEo8BoSbsDGwejg6VUJsKEdneaoTUo= -github.com/rabbitmq/amqp091-go v1.7.0/go.mod h1:wfClAtY0C7bOHxd3GjmF26jEHn+rR/0B3+YV+Vn9/NI= +github.com/rabbitmq/amqp091-go v1.8.0 h1:GBFy5PpLQ5jSVVSYv8ecHGqeX7UTLYR4ItQbDCss9MM= +github.com/rabbitmq/amqp091-go v1.8.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= -go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/channelmanager/channel_manager.go b/internal/channelmanager/channel_manager.go index 67faf0a..81a9759 100644 --- a/internal/channelmanager/channel_manager.go +++ b/internal/channelmanager/channel_manager.go @@ -5,10 +5,10 @@ import ( "sync" "time" + "github.com/DizoftTeam/go-rabbitmq/internal/connectionmanager" + "github.com/DizoftTeam/go-rabbitmq/internal/dispatcher" + "github.com/DizoftTeam/go-rabbitmq/internal/logger" amqp "github.com/rabbitmq/amqp091-go" - "github.com/wagslane/go-rabbitmq/internal/connectionmanager" - "github.com/wagslane/go-rabbitmq/internal/dispatcher" - "github.com/wagslane/go-rabbitmq/internal/logger" ) // ChannelManager - diff --git a/internal/connectionmanager/connection_manager.go b/internal/connectionmanager/connection_manager.go index fce1f2b..bfbd513 100644 --- a/internal/connectionmanager/connection_manager.go +++ b/internal/connectionmanager/connection_manager.go @@ -4,9 +4,9 @@ import ( "sync" "time" + "github.com/DizoftTeam/go-rabbitmq/internal/dispatcher" + "github.com/DizoftTeam/go-rabbitmq/internal/logger" amqp "github.com/rabbitmq/amqp091-go" - "github.com/wagslane/go-rabbitmq/internal/dispatcher" - "github.com/wagslane/go-rabbitmq/internal/logger" ) // ConnectionManager - diff --git a/logger.go b/logger.go index 2c3f231..4960129 100644 --- a/logger.go +++ b/logger.go @@ -4,7 +4,7 @@ import ( "fmt" "log" - "github.com/wagslane/go-rabbitmq/internal/logger" + "github.com/DizoftTeam/go-rabbitmq/internal/logger" ) // Logger is describes a logging structure. It can be set using diff --git a/publish.go b/publish.go index 8954018..bee7828 100644 --- a/publish.go +++ b/publish.go @@ -6,9 +6,9 @@ import ( "fmt" "sync" + "github.com/DizoftTeam/go-rabbitmq/internal/channelmanager" + "github.com/DizoftTeam/go-rabbitmq/internal/connectionmanager" amqp "github.com/rabbitmq/amqp091-go" - "github.com/wagslane/go-rabbitmq/internal/channelmanager" - "github.com/wagslane/go-rabbitmq/internal/connectionmanager" ) // DeliveryMode. Transient means higher throughput but messages will not be diff --git a/vendor/github.com/rabbitmq/amqp091-go/CHANGELOG.md b/vendor/github.com/rabbitmq/amqp091-go/CHANGELOG.md index 1165775..b59599d 100644 --- a/vendor/github.com/rabbitmq/amqp091-go/CHANGELOG.md +++ b/vendor/github.com/rabbitmq/amqp091-go/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## [v1.7.0](https://github.com/rabbitmq/amqp091-go/tree/v1.7.0) (2023-02-09) + +[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.6.1...v1.7.0) + +**Closed issues:** + +- \#31 resurfacing \(?\) [\#170](https://github.com/rabbitmq/amqp091-go/issues/170) +- Deprecate QueueInspect [\#167](https://github.com/rabbitmq/amqp091-go/issues/167) +- v1.6.0 causing rabbit connection errors [\#160](https://github.com/rabbitmq/amqp091-go/issues/160) + +**Merged pull requests:** + +- Set channels and allocator to nil in shutdown [\#172](https://github.com/rabbitmq/amqp091-go/pull/172) ([lukebakken](https://github.com/lukebakken)) +- Fix racing in Open [\#171](https://github.com/rabbitmq/amqp091-go/pull/171) ([Zerpet](https://github.com/Zerpet)) +- adding go 1.20 to tests [\#169](https://github.com/rabbitmq/amqp091-go/pull/169) ([halilylm](https://github.com/halilylm)) +- Deprecate the QueueInspect function [\#168](https://github.com/rabbitmq/amqp091-go/pull/168) ([lukebakken](https://github.com/lukebakken)) +- Check if channel is nil before updating it [\#150](https://github.com/rabbitmq/amqp091-go/pull/150) ([julienschmidt](https://github.com/julienschmidt)) + ## [v1.6.1](https://github.com/rabbitmq/amqp091-go/tree/v1.6.1) (2023-02-01) [Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.6.1-rc.2...v1.6.1) diff --git a/vendor/github.com/rabbitmq/amqp091-go/CONTRIBUTING.md b/vendor/github.com/rabbitmq/amqp091-go/CONTRIBUTING.md index ed1b971..ec86fe5 100644 --- a/vendor/github.com/rabbitmq/amqp091-go/CONTRIBUTING.md +++ b/vendor/github.com/rabbitmq/amqp091-go/CONTRIBUTING.md @@ -9,11 +9,13 @@ Here is the recommended workflow: 1. Run Static Checks 1. Run integration tests (see below) 1. **Implement tests** -1. Implement fixs -1. Commit your changes (`git commit -am 'Add some feature'`) +1. Implement fixes +1. Commit your changes. Use a [good, descriptive, commit message][good-commit]. 1. Push to a branch (`git push -u origin my-new-feature`) 1. Submit a pull request +[good-commit]: https://cbea.ms/git-commit/ + ## Running Static Checks golangci-lint must be installed to run the static checks. See [installation @@ -43,6 +45,18 @@ The integration tests can be run via: make tests ``` +Some tests require access to `rabbitmqctl` CLI. Use the environment variable +`RABBITMQ_RABBITMQCTL_PATH=/some/path/to/rabbitmqctl` to run those tests. + +If you have Docker available in your machine, you can run: + +```shell +make tests-docker +``` + +This target will start a RabbitMQ container, run the test suite with the environment +variable setup, and stop RabbitMQ container after a successful run. + All integration tests should use the `integrationConnection(...)` test helpers defined in `integration_test.go` to setup the integration environment and logging. diff --git a/vendor/github.com/rabbitmq/amqp091-go/Makefile b/vendor/github.com/rabbitmq/amqp091-go/Makefile index 7342731..69e9e2b 100644 --- a/vendor/github.com/rabbitmq/amqp091-go/Makefile +++ b/vendor/github.com/rabbitmq/amqp091-go/Makefile @@ -19,6 +19,11 @@ fmt: ## Run go fmt against code tests: ## Run all tests and requires a running rabbitmq-server. Use GO_TEST_FLAGS to add extra flags to go test go test -race -v -tags integration $(GO_TEST_FLAGS) +.PHONY: tests-docker +tests-docker: rabbitmq-server + RABBITMQ_RABBITMQCTL_PATH="DOCKER:$(CONTAINER_NAME)" go test -race -v -tags integration $(GO_TEST_FLAGS) + $(MAKE) stop-rabbitmq-server + .PHONY: check check: golangci-lint run ./... diff --git a/vendor/github.com/rabbitmq/amqp091-go/channel.go b/vendor/github.com/rabbitmq/amqp091-go/channel.go index 8ba9bab..ae6f2d1 100644 --- a/vendor/github.com/rabbitmq/amqp091-go/channel.go +++ b/vendor/github.com/rabbitmq/amqp091-go/channel.go @@ -1435,6 +1435,11 @@ func (ch *Channel) PublishWithDeferredConfirmWithContext(ctx context.Context, ex ch.m.Lock() defer ch.m.Unlock() + var dc *DeferredConfirmation + if ch.confirming { + dc = ch.confirms.publish() + } + if err := ch.send(&basicPublish{ Exchange: exchange, RoutingKey: key, @@ -1457,14 +1462,13 @@ func (ch *Channel) PublishWithDeferredConfirmWithContext(ctx context.Context, ex AppId: msg.AppId, }, }); err != nil { + if ch.confirming { + ch.confirms.unpublish() + } return nil, err } - if ch.confirming { - return ch.confirms.Publish(), nil - } - - return nil, nil + return dc, nil } /* diff --git a/vendor/github.com/rabbitmq/amqp091-go/confirms.go b/vendor/github.com/rabbitmq/amqp091-go/confirms.go index f9973b7..577e042 100644 --- a/vendor/github.com/rabbitmq/amqp091-go/confirms.go +++ b/vendor/github.com/rabbitmq/amqp091-go/confirms.go @@ -39,7 +39,7 @@ func (c *confirms) Listen(l chan Confirmation) { } // Publish increments the publishing counter -func (c *confirms) Publish() *DeferredConfirmation { +func (c *confirms) publish() *DeferredConfirmation { c.publishedMut.Lock() defer c.publishedMut.Unlock() @@ -47,6 +47,15 @@ func (c *confirms) Publish() *DeferredConfirmation { return c.deferredConfirmations.Add(c.published) } +// unpublish decrements the publishing counter and removes the +// DeferredConfirmation. It must be called immediately after a publish fails. +func (c *confirms) unpublish() { + c.publishedMut.Lock() + defer c.publishedMut.Unlock() + c.deferredConfirmations.remove(c.published) + c.published-- +} + // confirm confirms one publishing, increments the expecting delivery tag, and // removes bookkeeping for that delivery tag. func (c *confirms) confirm(confirmation Confirmation) { @@ -135,6 +144,18 @@ func (d *deferredConfirmations) Add(tag uint64) *DeferredConfirmation { return dc } +// remove is only used to drop a tag whose publish failed +func (d *deferredConfirmations) remove(tag uint64) { + d.m.Lock() + defer d.m.Unlock() + dc, found := d.confirmations[tag] + if !found { + return + } + close(dc.done) + delete(d.confirmations, tag) +} + func (d *deferredConfirmations) Confirm(confirmation Confirmation) { d.m.Lock() defer d.m.Unlock() diff --git a/vendor/github.com/rabbitmq/amqp091-go/connection.go b/vendor/github.com/rabbitmq/amqp091-go/connection.go index def2260..abe4b02 100644 --- a/vendor/github.com/rabbitmq/amqp091-go/connection.go +++ b/vendor/github.com/rabbitmq/amqp091-go/connection.go @@ -399,12 +399,47 @@ func (c *Connection) Close() error { ) } +// CloseDeadline requests and waits for the response to close this AMQP connection. +// +// Accepts a deadline for waiting the server response. The deadline is passed +// to the low-level connection i.e. network socket. +// +// Regardless of the error returned, the connection is considered closed, and it +// should not be used after calling this function. +// +// In the event of an I/O timeout, connection-closed listeners are NOT informed. +// +// After returning from this call, all resources associated with this connection, +// including the underlying io, Channels, Notify listeners and Channel consumers +// will also be closed. +func (c *Connection) CloseDeadline(deadline time.Time) error { + if c.IsClosed() { + return ErrClosed + } + + defer c.shutdown(nil) + + err := c.setDeadline(deadline) + if err != nil { + return err + } + + return c.call( + &connectionClose{ + ReplyCode: replySuccess, + ReplyText: "kthxbai", + }, + &connectionCloseOk{}, + ) +} + func (c *Connection) closeWith(err *Error) error { if c.IsClosed() { return ErrClosed } defer c.shutdown(err) + return c.call( &connectionClose{ ReplyCode: uint16(err.Code), @@ -420,6 +455,18 @@ func (c *Connection) IsClosed() bool { return atomic.LoadInt32(&c.closed) == 1 } +// setDeadline is a wrapper to type assert Connection.conn and set an I/O +// deadline in the underlying TCP connection socket, by calling +// net.Conn.SetDeadline(). It returns an error, in case the type assertion fails, +// although this should never happen. +func (c *Connection) setDeadline(t time.Time) error { + con, ok := c.conn.(net.Conn) + if !ok { + return errInvalidTypeAssertion + } + return con.SetDeadline(t) +} + func (c *Connection) send(f frame) error { if c.IsClosed() { return ErrClosed diff --git a/vendor/github.com/rabbitmq/amqp091-go/consumers.go b/vendor/github.com/rabbitmq/amqp091-go/consumers.go index 8c23fad..c352fec 100644 --- a/vendor/github.com/rabbitmq/amqp091-go/consumers.go +++ b/vendor/github.com/rabbitmq/amqp091-go/consumers.go @@ -75,6 +75,33 @@ func (subs *consumers) buffer(in chan *Delivery, out chan Delivery) { } case out <- *queue[0]: + /* + * https://github.com/rabbitmq/amqp091-go/issues/179 + * https://github.com/rabbitmq/amqp091-go/pull/180 + * + * Comment from @lars-t-hansen: + * + * Given Go's slice semantics, and barring any information + * available to the compiler that proves that queue is the only + * pointer to the memory it references, the only meaning that + * queue = queue[1:] can have is basically queue += sizeof(queue + * element), ie, it bumps a pointer. Looking at the generated + * code for a simple example (on ARM64 in this case) bears this + * out. So what we're left with is an array that we have a + * pointer into the middle of. When the GC traces this pointer, + * it too does not know whether the array has multiple + * referents, and so its only sensible choice is to find the + * beginning of the array, and if the array is not already + * visited, mark every element in it, including the "dead" + * pointer. + * + * (Depending on the program dynamics, an element may eventually + * be appended to the queue when the queue is at capacity, and + * in this case the live elements are copied into a new array + * and the old array is left to be GC'd eventually, along with + * the dead object. But that can take time.) + */ + queue[0] = nil queue = queue[1:] } } diff --git a/vendor/github.com/rabbitmq/amqp091-go/types.go b/vendor/github.com/rabbitmq/amqp091-go/types.go index 427eefb..e8d8986 100644 --- a/vendor/github.com/rabbitmq/amqp091-go/types.go +++ b/vendor/github.com/rabbitmq/amqp091-go/types.go @@ -63,6 +63,11 @@ var ( ErrFieldType = &Error{Code: SyntaxError, Reason: "unsupported table field type"} ) +// internal errors used inside the library +var ( + errInvalidTypeAssertion = &Error{Code: InternalError, Reason: "type assertion unsuccessful", Server: false, Recover: true} +) + // Error captures the code and reason a channel or connection has been closed // by the server. type Error struct { diff --git a/vendor/modules.txt b/vendor/modules.txt index 8765d0d..ca577cd 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,3 +1,3 @@ -# github.com/rabbitmq/amqp091-go v1.7.0 +# github.com/rabbitmq/amqp091-go v1.8.0 ## explicit; go 1.16 github.com/rabbitmq/amqp091-go From 6128c9e53ec88e9bb6f874a206a4905ae60e49c0 Mon Sep 17 00:00:00 2001 From: WiRight Date: Mon, 24 Apr 2023 11:02:04 +0300 Subject: [PATCH 02/12] Add Declarator --- declare.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/declare.go b/declare.go index 7379d4c..5b7dd2c 100644 --- a/declare.go +++ b/declare.go @@ -1,9 +1,46 @@ package rabbitmq import ( + "errors" + "fmt" + "github.com/DizoftTeam/go-rabbitmq/internal/channelmanager" ) +type Declarator struct { + chanManager *channelmanager.ChannelManager +} + +func NewDeclarator(conn *Conn) (*Declarator, error) { + defaultOptions := getDefaultPublisherOptions() + options := &defaultOptions + + if conn.connectionManager == nil { + return nil, errors.New("connection manager can't be nil") + } + + chanManager, err := channelmanager.NewChannelManager(conn.connectionManager, options.Logger, conn.connectionManager.ReconnectInterval) + if err != nil { + return nil, err + } + + result := &Declarator{ + chanManager: chanManager, + } + + return result, nil +} + +func (d *Declarator) Declare(options ConsumerOptions) error { + err := declareBindings(d.chanManager, options) + + if err != nil { + return fmt.Errorf("declare bindings failed: %w", err) + } + + return nil +} + func declareQueue(chanManager *channelmanager.ChannelManager, options QueueOptions) error { if !options.Declare { return nil From 3db20f637733ea9fbfe3e1516c492b45b5c66cce Mon Sep 17 00:00:00 2001 From: WiRight Date: Mon, 24 Apr 2023 11:09:41 +0300 Subject: [PATCH 03/12] Add options to declarator --- declare.go | 15 +- .../github.com/rabbitmq/amqp091-go/.gitignore | 6 - .../rabbitmq/amqp091-go/.golangci.yml | 3 - .../rabbitmq/amqp091-go/CHANGELOG.md | 267 -- .../rabbitmq/amqp091-go/CODE_OF_CONDUCT.md | 77 - .../rabbitmq/amqp091-go/CONTRIBUTING.md | 62 - vendor/github.com/rabbitmq/amqp091-go/LICENSE | 25 - .../github.com/rabbitmq/amqp091-go/Makefile | 41 - .../github.com/rabbitmq/amqp091-go/README.md | 105 - .../github.com/rabbitmq/amqp091-go/RELEASE.md | 5 - .../rabbitmq/amqp091-go/allocator.go | 111 - vendor/github.com/rabbitmq/amqp091-go/auth.go | 83 - .../github.com/rabbitmq/amqp091-go/certs.sh | 159 - .../rabbitmq/amqp091-go/change_version.sh | 4 - .../github.com/rabbitmq/amqp091-go/channel.go | 1709 --------- .../rabbitmq/amqp091-go/confirms.go | 238 -- .../rabbitmq/amqp091-go/connection.go | 1099 ------ .../rabbitmq/amqp091-go/consumers.go | 169 - .../rabbitmq/amqp091-go/delivery.go | 173 - vendor/github.com/rabbitmq/amqp091-go/doc.go | 165 - vendor/github.com/rabbitmq/amqp091-go/fuzz.go | 23 - vendor/github.com/rabbitmq/amqp091-go/gen.sh | 2 - vendor/github.com/rabbitmq/amqp091-go/log.go | 23 - vendor/github.com/rabbitmq/amqp091-go/read.go | 450 --- .../github.com/rabbitmq/amqp091-go/return.go | 64 - .../github.com/rabbitmq/amqp091-go/spec091.go | 3382 ----------------- .../github.com/rabbitmq/amqp091-go/types.go | 514 --- vendor/github.com/rabbitmq/amqp091-go/uri.go | 196 - .../github.com/rabbitmq/amqp091-go/write.go | 427 --- vendor/modules.txt | 3 - 30 files changed, 9 insertions(+), 9591 deletions(-) delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/.gitignore delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/.golangci.yml delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/CHANGELOG.md delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/CODE_OF_CONDUCT.md delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/CONTRIBUTING.md delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/LICENSE delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/Makefile delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/README.md delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/RELEASE.md delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/allocator.go delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/auth.go delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/certs.sh delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/change_version.sh delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/channel.go delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/confirms.go delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/connection.go delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/consumers.go delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/delivery.go delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/doc.go delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/fuzz.go delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/gen.sh delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/log.go delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/read.go delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/return.go delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/spec091.go delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/types.go delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/uri.go delete mode 100644 vendor/github.com/rabbitmq/amqp091-go/write.go delete mode 100644 vendor/modules.txt diff --git a/declare.go b/declare.go index 5b7dd2c..08ff897 100644 --- a/declare.go +++ b/declare.go @@ -12,14 +12,11 @@ type Declarator struct { } func NewDeclarator(conn *Conn) (*Declarator, error) { - defaultOptions := getDefaultPublisherOptions() - options := &defaultOptions - if conn.connectionManager == nil { return nil, errors.New("connection manager can't be nil") } - chanManager, err := channelmanager.NewChannelManager(conn.connectionManager, options.Logger, conn.connectionManager.ReconnectInterval) + chanManager, err := channelmanager.NewChannelManager(conn.connectionManager, &stdDebugLogger{}, conn.connectionManager.ReconnectInterval) if err != nil { return nil, err } @@ -31,8 +28,14 @@ func NewDeclarator(conn *Conn) (*Declarator, error) { return result, nil } -func (d *Declarator) Declare(options ConsumerOptions) error { - err := declareBindings(d.chanManager, options) +func (d *Declarator) Declare(queue string, optionFuncs ...func(*ConsumerOptions)) error { + defaultOptions := getDefaultConsumerOptions(queue) + options := &defaultOptions + for _, optionFunc := range optionFuncs { + optionFunc(options) + } + + err := declareBindings(d.chanManager, *options) if err != nil { return fmt.Errorf("declare bindings failed: %w", err) diff --git a/vendor/github.com/rabbitmq/amqp091-go/.gitignore b/vendor/github.com/rabbitmq/amqp091-go/.gitignore deleted file mode 100644 index a93cced..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -certs/* -spec/spec -examples/simple-consumer/simple-consumer -examples/simple-producer/simple-producer - -.idea/ diff --git a/vendor/github.com/rabbitmq/amqp091-go/.golangci.yml b/vendor/github.com/rabbitmq/amqp091-go/.golangci.yml deleted file mode 100644 index 4341bcf..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/.golangci.yml +++ /dev/null @@ -1,3 +0,0 @@ -run: - build-tags: - - integration diff --git a/vendor/github.com/rabbitmq/amqp091-go/CHANGELOG.md b/vendor/github.com/rabbitmq/amqp091-go/CHANGELOG.md deleted file mode 100644 index b59599d..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/CHANGELOG.md +++ /dev/null @@ -1,267 +0,0 @@ -# Changelog - -## [v1.7.0](https://github.com/rabbitmq/amqp091-go/tree/v1.7.0) (2023-02-09) - -[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.6.1...v1.7.0) - -**Closed issues:** - -- \#31 resurfacing \(?\) [\#170](https://github.com/rabbitmq/amqp091-go/issues/170) -- Deprecate QueueInspect [\#167](https://github.com/rabbitmq/amqp091-go/issues/167) -- v1.6.0 causing rabbit connection errors [\#160](https://github.com/rabbitmq/amqp091-go/issues/160) - -**Merged pull requests:** - -- Set channels and allocator to nil in shutdown [\#172](https://github.com/rabbitmq/amqp091-go/pull/172) ([lukebakken](https://github.com/lukebakken)) -- Fix racing in Open [\#171](https://github.com/rabbitmq/amqp091-go/pull/171) ([Zerpet](https://github.com/Zerpet)) -- adding go 1.20 to tests [\#169](https://github.com/rabbitmq/amqp091-go/pull/169) ([halilylm](https://github.com/halilylm)) -- Deprecate the QueueInspect function [\#168](https://github.com/rabbitmq/amqp091-go/pull/168) ([lukebakken](https://github.com/lukebakken)) -- Check if channel is nil before updating it [\#150](https://github.com/rabbitmq/amqp091-go/pull/150) ([julienschmidt](https://github.com/julienschmidt)) - -## [v1.6.1](https://github.com/rabbitmq/amqp091-go/tree/v1.6.1) (2023-02-01) - -[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.6.1-rc.2...v1.6.1) - -**Merged pull requests:** - -- Update Makefile targets related to RabbitMQ [\#163](https://github.com/rabbitmq/amqp091-go/pull/163) ([Zerpet](https://github.com/Zerpet)) - -## [v1.6.1-rc.2](https://github.com/rabbitmq/amqp091-go/tree/v1.6.1-rc.2) (2023-01-31) - -[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.6.1-rc.1...v1.6.1-rc.2) - -**Merged pull requests:** - -- Do not overly protect writes [\#162](https://github.com/rabbitmq/amqp091-go/pull/162) ([lukebakken](https://github.com/lukebakken)) - -## [v1.6.1-rc.1](https://github.com/rabbitmq/amqp091-go/tree/v1.6.1-rc.1) (2023-01-31) - -[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.6.0...v1.6.1-rc.1) - -**Closed issues:** - -- Calling Channel\(\) on an empty connection panics [\#148](https://github.com/rabbitmq/amqp091-go/issues/148) - -**Merged pull requests:** - -- Ensure flush happens and correctly lock connection for a series of unflushed writes [\#161](https://github.com/rabbitmq/amqp091-go/pull/161) ([lukebakken](https://github.com/lukebakken)) - -## [v1.6.0](https://github.com/rabbitmq/amqp091-go/tree/v1.6.0) (2023-01-20) - -[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.5.0...v1.6.0) - -**Implemented enhancements:** - -- Add constants for Queue arguments [\#145](https://github.com/rabbitmq/amqp091-go/pull/145) ([Zerpet](https://github.com/Zerpet)) - -**Closed issues:** - -- README not up to date [\#154](https://github.com/rabbitmq/amqp091-go/issues/154) -- Allow re-using default connection config \(custom properties\) [\#152](https://github.com/rabbitmq/amqp091-go/issues/152) -- Rename package name to amqp in V2 [\#151](https://github.com/rabbitmq/amqp091-go/issues/151) -- Helper types to declare quorum queues [\#144](https://github.com/rabbitmq/amqp091-go/issues/144) -- Inefficient use of buffers reduces potential throughput for basicPublish with small messages. [\#141](https://github.com/rabbitmq/amqp091-go/issues/141) -- bug, close cause panic [\#130](https://github.com/rabbitmq/amqp091-go/issues/130) -- Publishing Headers are unable to store Table with slice values [\#125](https://github.com/rabbitmq/amqp091-go/issues/125) -- Example client can deadlock in Close due to unconsumed confirmations [\#122](https://github.com/rabbitmq/amqp091-go/issues/122) -- SAC not working properly [\#106](https://github.com/rabbitmq/amqp091-go/issues/106) - -**Merged pull requests:** - -- Add automatic CHANGELOG.md generation [\#158](https://github.com/rabbitmq/amqp091-go/pull/158) ([lukebakken](https://github.com/lukebakken)) -- Supply library-defined props with NewConnectionProperties [\#157](https://github.com/rabbitmq/amqp091-go/pull/157) ([slagiewka](https://github.com/slagiewka)) -- Fix linter warnings [\#156](https://github.com/rabbitmq/amqp091-go/pull/156) ([Zerpet](https://github.com/Zerpet)) -- Remove outdated information from README [\#155](https://github.com/rabbitmq/amqp091-go/pull/155) ([scriptcoded](https://github.com/scriptcoded)) -- Add example producer using DeferredConfirm [\#149](https://github.com/rabbitmq/amqp091-go/pull/149) ([Zerpet](https://github.com/Zerpet)) -- Ensure code is formatted [\#147](https://github.com/rabbitmq/amqp091-go/pull/147) ([lukebakken](https://github.com/lukebakken)) -- Fix inefficient use of buffers that reduces the potential throughput of basicPublish [\#142](https://github.com/rabbitmq/amqp091-go/pull/142) ([fadams](https://github.com/fadams)) -- Do not embed context in DeferredConfirmation [\#140](https://github.com/rabbitmq/amqp091-go/pull/140) ([tie](https://github.com/tie)) -- Add constant for default exchange [\#139](https://github.com/rabbitmq/amqp091-go/pull/139) ([marlongerson](https://github.com/marlongerson)) -- Fix indentation and remove unnecessary instructions [\#138](https://github.com/rabbitmq/amqp091-go/pull/138) ([alraujo](https://github.com/alraujo)) -- Remove unnecessary instruction [\#135](https://github.com/rabbitmq/amqp091-go/pull/135) ([alraujo](https://github.com/alraujo)) -- Fix example client to avoid deadlock in Close [\#123](https://github.com/rabbitmq/amqp091-go/pull/123) ([Zerpet](https://github.com/Zerpet)) -- Bump go.uber.org/goleak from 1.1.12 to 1.2.0 [\#116](https://github.com/rabbitmq/amqp091-go/pull/116) ([dependabot[bot]](https://github.com/apps/dependabot)) - -## [v1.5.0](https://github.com/rabbitmq/amqp091-go/tree/v1.5.0) (2022-09-07) - -[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.4.0...v1.5.0) - -**Implemented enhancements:** - -- Provide a friendly way to set connection name [\#105](https://github.com/rabbitmq/amqp091-go/issues/105) - -**Closed issues:** - -- Support connection.update-secret [\#107](https://github.com/rabbitmq/amqp091-go/issues/107) -- Example Client: Implementation of a Consumer with reconnection support [\#40](https://github.com/rabbitmq/amqp091-go/issues/40) - -**Merged pull requests:** - -- use PublishWithContext instead of Publish [\#115](https://github.com/rabbitmq/amqp091-go/pull/115) ([Gsantomaggio](https://github.com/Gsantomaggio)) -- Add support for connection.update-secret [\#114](https://github.com/rabbitmq/amqp091-go/pull/114) ([Zerpet](https://github.com/Zerpet)) -- Remove warning on RabbitMQ tutorials in go [\#113](https://github.com/rabbitmq/amqp091-go/pull/113) ([ChunyiLyu](https://github.com/ChunyiLyu)) -- Update AMQP Spec [\#110](https://github.com/rabbitmq/amqp091-go/pull/110) ([Zerpet](https://github.com/Zerpet)) -- Add an example of reliable consumer [\#109](https://github.com/rabbitmq/amqp091-go/pull/109) ([Zerpet](https://github.com/Zerpet)) -- Add convenience function to set connection name [\#108](https://github.com/rabbitmq/amqp091-go/pull/108) ([Zerpet](https://github.com/Zerpet)) - -## [v1.4.0](https://github.com/rabbitmq/amqp091-go/tree/v1.4.0) (2022-07-19) - -[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.3.4...v1.4.0) - -**Closed issues:** - -- target machine actively refused connection [\#99](https://github.com/rabbitmq/amqp091-go/issues/99) -- 504 channel/connection is not open error occurred in multiple connection with same rabbitmq service [\#97](https://github.com/rabbitmq/amqp091-go/issues/97) -- Add possible cancel of DeferredConfirmation [\#92](https://github.com/rabbitmq/amqp091-go/issues/92) -- Documentation [\#89](https://github.com/rabbitmq/amqp091-go/issues/89) -- Channel Close gets stuck after closing a connection \(via management UI\) [\#88](https://github.com/rabbitmq/amqp091-go/issues/88) -- this library has same issue [\#83](https://github.com/rabbitmq/amqp091-go/issues/83) -- Provide a logging interface [\#81](https://github.com/rabbitmq/amqp091-go/issues/81) -- 1.4.0 release checklist [\#77](https://github.com/rabbitmq/amqp091-go/issues/77) -- Data race in the client example [\#72](https://github.com/rabbitmq/amqp091-go/issues/72) -- reader go routine hangs and leaks when Connection.Close\(\) is called multiple times [\#69](https://github.com/rabbitmq/amqp091-go/issues/69) -- Support auto-reconnect and cluster [\#65](https://github.com/rabbitmq/amqp091-go/issues/65) -- Connection/Channel Deadlock [\#32](https://github.com/rabbitmq/amqp091-go/issues/32) -- Closing connection and/or channel hangs NotifyPublish is used [\#21](https://github.com/rabbitmq/amqp091-go/issues/21) -- Consumer channel isn't closed in the event of unexpected disconnection [\#18](https://github.com/rabbitmq/amqp091-go/issues/18) - -**Merged pull requests:** - -- fix race condition with context close and confirm at the same time on DeferredConfirmation. [\#101](https://github.com/rabbitmq/amqp091-go/pull/101) ([sapk](https://github.com/sapk)) -- Add build TLS config from URI [\#98](https://github.com/rabbitmq/amqp091-go/pull/98) ([reddec](https://github.com/reddec)) -- Use context for Publish methods [\#96](https://github.com/rabbitmq/amqp091-go/pull/96) ([sapk](https://github.com/sapk)) -- Added function to get the remote peer's IP address \(conn.RemoteAddr\(\)\) [\#95](https://github.com/rabbitmq/amqp091-go/pull/95) ([rabb1t](https://github.com/rabb1t)) -- Update connection documentation [\#90](https://github.com/rabbitmq/amqp091-go/pull/90) ([Zerpet](https://github.com/Zerpet)) -- Revert test to demonstrate actual bug [\#87](https://github.com/rabbitmq/amqp091-go/pull/87) ([lukebakken](https://github.com/lukebakken)) -- Minor improvements to examples [\#86](https://github.com/rabbitmq/amqp091-go/pull/86) ([lukebakken](https://github.com/lukebakken)) -- Do not skip flaky test in CI [\#85](https://github.com/rabbitmq/amqp091-go/pull/85) ([lukebakken](https://github.com/lukebakken)) -- Add logging [\#84](https://github.com/rabbitmq/amqp091-go/pull/84) ([lukebakken](https://github.com/lukebakken)) -- Add a win32 build [\#82](https://github.com/rabbitmq/amqp091-go/pull/82) ([lukebakken](https://github.com/lukebakken)) -- channel: return nothing instead of always a nil-error in receive methods [\#80](https://github.com/rabbitmq/amqp091-go/pull/80) ([fho](https://github.com/fho)) -- update the contributing & readme files, improve makefile [\#79](https://github.com/rabbitmq/amqp091-go/pull/79) ([fho](https://github.com/fho)) -- Fix lint errors [\#78](https://github.com/rabbitmq/amqp091-go/pull/78) ([lukebakken](https://github.com/lukebakken)) -- ci: run golangci-lint [\#76](https://github.com/rabbitmq/amqp091-go/pull/76) ([fho](https://github.com/fho)) -- ci: run test via make & remove travis CI config [\#75](https://github.com/rabbitmq/amqp091-go/pull/75) ([fho](https://github.com/fho)) -- ci: run tests with race detector [\#74](https://github.com/rabbitmq/amqp091-go/pull/74) ([fho](https://github.com/fho)) -- Detect go routine leaks in integration testcases [\#73](https://github.com/rabbitmq/amqp091-go/pull/73) ([fho](https://github.com/fho)) -- connection: fix: reader go-routine is leaked on connection close [\#70](https://github.com/rabbitmq/amqp091-go/pull/70) ([fho](https://github.com/fho)) -- adding best practises for NotifyPublish for issue\_21 scenario [\#68](https://github.com/rabbitmq/amqp091-go/pull/68) ([DanielePalaia](https://github.com/DanielePalaia)) -- Update Go version [\#67](https://github.com/rabbitmq/amqp091-go/pull/67) ([Zerpet](https://github.com/Zerpet)) -- Regenerate certs with SHA256 to fix test with Go 1.18+ [\#66](https://github.com/rabbitmq/amqp091-go/pull/66) ([anthonyfok](https://github.com/anthonyfok)) - -## [v1.3.4](https://github.com/rabbitmq/amqp091-go/tree/v1.3.4) (2022-04-01) - -[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.3.3...v1.3.4) - -**Merged pull requests:** - -- bump version to 1.3.4 [\#63](https://github.com/rabbitmq/amqp091-go/pull/63) ([DanielePalaia](https://github.com/DanielePalaia)) -- updating doc [\#62](https://github.com/rabbitmq/amqp091-go/pull/62) ([DanielePalaia](https://github.com/DanielePalaia)) - -## [v1.3.3](https://github.com/rabbitmq/amqp091-go/tree/v1.3.3) (2022-04-01) - -[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.3.2...v1.3.3) - -**Closed issues:** - -- Add Client Version [\#49](https://github.com/rabbitmq/amqp091-go/issues/49) -- OpenTelemetry Propagation [\#22](https://github.com/rabbitmq/amqp091-go/issues/22) - -**Merged pull requests:** - -- bump buildVersion for release [\#61](https://github.com/rabbitmq/amqp091-go/pull/61) ([DanielePalaia](https://github.com/DanielePalaia)) -- adding documentation for notifyClose best pratices [\#60](https://github.com/rabbitmq/amqp091-go/pull/60) ([DanielePalaia](https://github.com/DanielePalaia)) -- adding documentation on NotifyClose of connection and channel to enfo… [\#59](https://github.com/rabbitmq/amqp091-go/pull/59) ([DanielePalaia](https://github.com/DanielePalaia)) - -## [v1.3.2](https://github.com/rabbitmq/amqp091-go/tree/v1.3.2) (2022-03-28) - -[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.3.1...v1.3.2) - -**Closed issues:** - -- Potential race condition in Connection module [\#31](https://github.com/rabbitmq/amqp091-go/issues/31) - -**Merged pull requests:** - -- bump versioning to 1.3.2 [\#58](https://github.com/rabbitmq/amqp091-go/pull/58) ([DanielePalaia](https://github.com/DanielePalaia)) - -## [v1.3.1](https://github.com/rabbitmq/amqp091-go/tree/v1.3.1) (2022-03-25) - -[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.3.0...v1.3.1) - -**Closed issues:** - -- Possible deadlock on DeferredConfirmation.Wait\(\) [\#46](https://github.com/rabbitmq/amqp091-go/issues/46) -- Call to Delivery.Ack blocks indefinitely in case of disconnection [\#19](https://github.com/rabbitmq/amqp091-go/issues/19) -- Unexpacted behavor of channel.IsClosed\(\) [\#14](https://github.com/rabbitmq/amqp091-go/issues/14) -- A possible dead lock in connection close notification Go channel [\#11](https://github.com/rabbitmq/amqp091-go/issues/11) - -**Merged pull requests:** - -- These ones were the ones testing Open scenarios. The issue is that Op… [\#57](https://github.com/rabbitmq/amqp091-go/pull/57) ([DanielePalaia](https://github.com/DanielePalaia)) -- changing defaultVersion to buildVersion and create a simple change\_ve… [\#54](https://github.com/rabbitmq/amqp091-go/pull/54) ([DanielePalaia](https://github.com/DanielePalaia)) -- adding integration test for issue 11 [\#50](https://github.com/rabbitmq/amqp091-go/pull/50) ([DanielePalaia](https://github.com/DanielePalaia)) -- Remove the old link product [\#48](https://github.com/rabbitmq/amqp091-go/pull/48) ([Gsantomaggio](https://github.com/Gsantomaggio)) -- Fix deadlock on DeferredConfirmations [\#47](https://github.com/rabbitmq/amqp091-go/pull/47) ([SpencerTorres](https://github.com/SpencerTorres)) -- Example client: Rename Stream\(\) to Consume\(\) to avoid confusion with RabbitMQ streams [\#39](https://github.com/rabbitmq/amqp091-go/pull/39) ([andygrunwald](https://github.com/andygrunwald)) -- Example client: Rename `name` to `queueName` to make the usage clear and explicit [\#38](https://github.com/rabbitmq/amqp091-go/pull/38) ([andygrunwald](https://github.com/andygrunwald)) -- Client example: Renamed concept "Session" to "Client" [\#37](https://github.com/rabbitmq/amqp091-go/pull/37) ([andygrunwald](https://github.com/andygrunwald)) -- delete unuseful code [\#36](https://github.com/rabbitmq/amqp091-go/pull/36) ([liutaot](https://github.com/liutaot)) -- Client Example: Fix closing order [\#35](https://github.com/rabbitmq/amqp091-go/pull/35) ([andygrunwald](https://github.com/andygrunwald)) -- Client example: Use instance logger instead of global logger [\#34](https://github.com/rabbitmq/amqp091-go/pull/34) ([andygrunwald](https://github.com/andygrunwald)) - -## [v1.3.0](https://github.com/rabbitmq/amqp091-go/tree/v1.3.0) (2022-01-13) - -[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.2.0...v1.3.0) - -**Closed issues:** - -- documentation of changes triggering version updates [\#29](https://github.com/rabbitmq/amqp091-go/issues/29) -- Persistent messages folder [\#27](https://github.com/rabbitmq/amqp091-go/issues/27) - -**Merged pull requests:** - -- Expose a method to enable out-of-order Publisher Confirms [\#33](https://github.com/rabbitmq/amqp091-go/pull/33) ([benmoss](https://github.com/benmoss)) -- Fix Signed 8-bit headers being treated as unsigned [\#26](https://github.com/rabbitmq/amqp091-go/pull/26) ([alex-goodisman](https://github.com/alex-goodisman)) - -## [v1.2.0](https://github.com/rabbitmq/amqp091-go/tree/v1.2.0) (2021-11-17) - -[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.1.0...v1.2.0) - -**Closed issues:** - -- No access to this vhost [\#24](https://github.com/rabbitmq/amqp091-go/issues/24) -- copyright issue? [\#12](https://github.com/rabbitmq/amqp091-go/issues/12) -- A possible dead lock when publishing message with confirmation [\#10](https://github.com/rabbitmq/amqp091-go/issues/10) -- Semver release [\#7](https://github.com/rabbitmq/amqp091-go/issues/7) - -**Merged pull requests:** - -- Fix deadlock between publishing and receiving confirms [\#25](https://github.com/rabbitmq/amqp091-go/pull/25) ([benmoss](https://github.com/benmoss)) -- Add GetNextPublishSeqNo for channel in confirm mode [\#23](https://github.com/rabbitmq/amqp091-go/pull/23) ([kamal-github](https://github.com/kamal-github)) -- Added support for cert-only login without user and password [\#20](https://github.com/rabbitmq/amqp091-go/pull/20) ([mihaitodor](https://github.com/mihaitodor)) - -## [v1.1.0](https://github.com/rabbitmq/amqp091-go/tree/v1.1.0) (2021-09-21) - -[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/ebd83429aa8cb06fa569473f623e87675f96d3a9...v1.1.0) - -**Closed issues:** - -- AMQPLAIN authentication does not work [\#15](https://github.com/rabbitmq/amqp091-go/issues/15) - -**Merged pull requests:** - -- Fix AMQPLAIN authentication mechanism [\#16](https://github.com/rabbitmq/amqp091-go/pull/16) ([hodbn](https://github.com/hodbn)) -- connection: clarify documented behavior of NotifyClose [\#13](https://github.com/rabbitmq/amqp091-go/pull/13) ([pabigot](https://github.com/pabigot)) -- Add a link to pkg.go.dev API docs [\#9](https://github.com/rabbitmq/amqp091-go/pull/9) ([benmoss](https://github.com/benmoss)) -- add test go version 1.16.x and 1.17.x [\#8](https://github.com/rabbitmq/amqp091-go/pull/8) ([k4n4ry](https://github.com/k4n4ry)) -- fix typos [\#6](https://github.com/rabbitmq/amqp091-go/pull/6) ([h44z](https://github.com/h44z)) -- Heartbeat interval should be timeout/2 [\#5](https://github.com/rabbitmq/amqp091-go/pull/5) ([ifo20](https://github.com/ifo20)) -- Exporting Channel State [\#4](https://github.com/rabbitmq/amqp091-go/pull/4) ([eibrunorodrigues](https://github.com/eibrunorodrigues)) -- Add codeql analysis [\#3](https://github.com/rabbitmq/amqp091-go/pull/3) ([MirahImage](https://github.com/MirahImage)) -- Add PR github action. [\#2](https://github.com/rabbitmq/amqp091-go/pull/2) ([MirahImage](https://github.com/MirahImage)) -- Update Copyright Statement [\#1](https://github.com/rabbitmq/amqp091-go/pull/1) ([rlewis24](https://github.com/rlewis24)) - - - -\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* diff --git a/vendor/github.com/rabbitmq/amqp091-go/CODE_OF_CONDUCT.md b/vendor/github.com/rabbitmq/amqp091-go/CODE_OF_CONDUCT.md deleted file mode 100644 index 24b5675..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,77 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in RabbitMQ Operator project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at oss-coc@vmware.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq - diff --git a/vendor/github.com/rabbitmq/amqp091-go/CONTRIBUTING.md b/vendor/github.com/rabbitmq/amqp091-go/CONTRIBUTING.md deleted file mode 100644 index ec86fe5..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/CONTRIBUTING.md +++ /dev/null @@ -1,62 +0,0 @@ -# Contributing - -## Workflow - -Here is the recommended workflow: - -1. Fork this repository, **github.com/rabbitmq/amqp091-go** -1. Create your feature branch (`git checkout -b my-new-feature`) -1. Run Static Checks -1. Run integration tests (see below) -1. **Implement tests** -1. Implement fixes -1. Commit your changes. Use a [good, descriptive, commit message][good-commit]. -1. Push to a branch (`git push -u origin my-new-feature`) -1. Submit a pull request - -[good-commit]: https://cbea.ms/git-commit/ - -## Running Static Checks - -golangci-lint must be installed to run the static checks. See [installation -docs](https://golangci-lint.run/usage/install/) for more information. - -The static checks can be run via: - -```shell -make checks -``` - -## Running Tests - -### Integration Tests - -Running the Integration tests require: - -* A running RabbitMQ node with all defaults: - [https://www.rabbitmq.com/download.html](https://www.rabbitmq.com/download.html) -* That the server is either reachable via `amqp://guest:guest@127.0.0.1:5672/` - or the environment variable `AMQP_URL` set to it's URL - (e.g.: `export AMQP_URL="amqp://guest:verysecretpasswd@rabbitmq-host:5772/`) - -The integration tests can be run via: - -```shell -make tests -``` - -Some tests require access to `rabbitmqctl` CLI. Use the environment variable -`RABBITMQ_RABBITMQCTL_PATH=/some/path/to/rabbitmqctl` to run those tests. - -If you have Docker available in your machine, you can run: - -```shell -make tests-docker -``` - -This target will start a RabbitMQ container, run the test suite with the environment -variable setup, and stop RabbitMQ container after a successful run. - -All integration tests should use the `integrationConnection(...)` test -helpers defined in `integration_test.go` to setup the integration environment -and logging. diff --git a/vendor/github.com/rabbitmq/amqp091-go/LICENSE b/vendor/github.com/rabbitmq/amqp091-go/LICENSE deleted file mode 100644 index 72fa55e..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -AMQP 0-9-1 Go Client -Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. - -Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/rabbitmq/amqp091-go/Makefile b/vendor/github.com/rabbitmq/amqp091-go/Makefile deleted file mode 100644 index 69e9e2b..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -.DEFAULT_GOAL := list - -# Insert a comment starting with '##' after a target, and it will be printed by 'make' and 'make list' -.PHONY: list -list: ## list Makefile targets - @echo "The most used targets: \n" - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' - -.PHONY: check-fmt -check-fmt: ## Ensure code is formatted - gofmt -l -d . # For the sake of debugging - test -z "$$(gofmt -l .)" - -.PHONY: fmt -fmt: ## Run go fmt against code - go fmt ./... - -.PHONY: tests -tests: ## Run all tests and requires a running rabbitmq-server. Use GO_TEST_FLAGS to add extra flags to go test - go test -race -v -tags integration $(GO_TEST_FLAGS) - -.PHONY: tests-docker -tests-docker: rabbitmq-server - RABBITMQ_RABBITMQCTL_PATH="DOCKER:$(CONTAINER_NAME)" go test -race -v -tags integration $(GO_TEST_FLAGS) - $(MAKE) stop-rabbitmq-server - -.PHONY: check -check: - golangci-lint run ./... - -CONTAINER_NAME ?= amqp091-go-rabbitmq - -.PHONY: rabbitmq-server -rabbitmq-server: ## Start a RabbitMQ server using Docker. Container name can be customised with CONTAINER_NAME=some-rabbit - docker run --detach --rm --name $(CONTAINER_NAME) \ - --publish 5672:5672 --publish 15672:15672 \ - --pull always rabbitmq:3-management - -.PHONY: stop-rabbitmq-server -stop-rabbitmq-server: ## Stop a RabbitMQ server using Docker. Container name can be customised with CONTAINER_NAME=some-rabbit - docker stop $(CONTAINER_NAME) diff --git a/vendor/github.com/rabbitmq/amqp091-go/README.md b/vendor/github.com/rabbitmq/amqp091-go/README.md deleted file mode 100644 index 6d3143f..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/README.md +++ /dev/null @@ -1,105 +0,0 @@ -# Go RabbitMQ Client Library - -[![amqp091-go](https://github.com/rabbitmq/amqp091-go/actions/workflows/tests.yml/badge.svg)](https://github.com/rabbitmq/amqp091-go/actions/workflows/tests.yml) -[![Go Reference](https://pkg.go.dev/badge/github.com/rabbitmq/amqp091-go.svg)](https://pkg.go.dev/github.com/rabbitmq/amqp091-go) -[![Go Report Card](https://goreportcard.com/badge/github.com/rabbitmq/amqp091-go)](https://goreportcard.com/report/github.com/rabbitmq/amqp091-go) - -This is a Go AMQP 0.9.1 client maintained by the [RabbitMQ core team](https://github.com/rabbitmq). -It was [originally developed by Sean Treadway](https://github.com/streadway/amqp). - -## Differences from streadway/amqp - -Some things are different compared to the original client, -others haven't changed. - -### Package Name - -This library uses a different package name. If moving from `streadway/amqp`, -using an alias may reduce the number of changes needed: - -``` go -amqp "github.com/rabbitmq/amqp091-go" -``` - -### License - -This client uses the same 2-clause BSD license as the original project. - -### Public API Evolution - - This client retains key API elements as practically possible. - It is, however, open to reasonable breaking public API changes suggested by the community. - We don't have the "no breaking public API changes ever" rule and fully recognize - that a good client API evolves over time. - - -## Project Maturity - -This project is based on a mature Go client that's been around for over a decade. - - -## Supported Go Versions - -This client supports two most recent Go release series. - - -## Supported RabbitMQ Versions - -This project supports RabbitMQ versions starting with `2.0` but primarily tested -against [currently supported RabbitMQ release series](https://www.rabbitmq.com/versions.html). - -Some features and behaviours may be server version-specific. - -## Goals - -Provide a functional interface that closely represents the AMQP 0.9.1 model -targeted to RabbitMQ as a server. This includes the minimum necessary to -interact the semantics of the protocol. - -## Non-goals - -Things not intended to be supported. - - * Auto reconnect and re-synchronization of client and server topologies. - * Reconnection would require understanding the error paths when the - topology cannot be declared on reconnect. This would require a new set - of types and code paths that are best suited at the call-site of this - package. AMQP has a dynamic topology that needs all peers to agree. If - this doesn't happen, the behavior is undefined. Instead of producing a - possible interface with undefined behavior, this package is designed to - be simple for the caller to implement the necessary connection-time - topology declaration so that reconnection is trivial and encapsulated in - the caller's application code. - * AMQP Protocol negotiation for forward or backward compatibility. - * 0.9.1 is stable and widely deployed. AMQP 1.0 is a divergent - specification (a different protocol) and belongs to a different library. - * Anything other than PLAIN and EXTERNAL authentication mechanisms. - * Keeping the mechanisms interface modular makes it possible to extend - outside of this package. If other mechanisms prove to be popular, then - we would accept patches to include them in this package. - * Support for [`basic.return` and `basic.ack` frame ordering](https://www.rabbitmq.com/confirms.html#when-publishes-are-confirmed). - This client uses Go channels for certain protocol events and ordering between - events sent to two different channels generally cannot be guaranteed. - -## Usage - -See the [_examples](_examples) subdirectory for simple producers and consumers executables. -If you have a use-case in mind which isn't well-represented by the examples, -please file an issue. - -## Documentation - - * [Godoc API reference](http://godoc.org/github.com/rabbitmq/amqp091-go) - * [RabbitMQ tutorials in Go](https://github.com/rabbitmq/rabbitmq-tutorials/tree/master/go) - -## Contributing - -Pull requests are very much welcomed. Create your pull request on a non-main -branch, make sure a test or example is included that covers your change, and -your commits represent coherent changes that include a reason for the change. - -See [CONTRIBUTING.md](CONTRIBUTING.md) for more information. - -## License - -BSD 2 clause, see LICENSE for more details. diff --git a/vendor/github.com/rabbitmq/amqp091-go/RELEASE.md b/vendor/github.com/rabbitmq/amqp091-go/RELEASE.md deleted file mode 100644 index a1b1ae0..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/RELEASE.md +++ /dev/null @@ -1,5 +0,0 @@ -## Changelog Generation - -``` -github_changelog_generator --token GITHUB-TOKEN -u rabbitmq -p amqp091-go --no-unreleased --release-branch main -``` diff --git a/vendor/github.com/rabbitmq/amqp091-go/allocator.go b/vendor/github.com/rabbitmq/amqp091-go/allocator.go deleted file mode 100644 index 0688e4b..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/allocator.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. -// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package amqp091 - -import ( - "bytes" - "fmt" - "math/big" -) - -const ( - free = 0 - allocated = 1 -) - -// allocator maintains a bitset of allocated numbers. -type allocator struct { - pool *big.Int - last int - low int - high int -} - -// NewAllocator reserves and frees integers out of a range between low and -// high. -// -// O(N) worst case space used, where N is maximum allocated, divided by -// sizeof(big.Word) -func newAllocator(low, high int) *allocator { - return &allocator{ - pool: big.NewInt(0), - last: low, - low: low, - high: high, - } -} - -// String returns a string describing the contents of the allocator like -// "allocator[low..high] reserved..until" -// -// O(N) where N is high-low -func (a allocator) String() string { - b := &bytes.Buffer{} - fmt.Fprintf(b, "allocator[%d..%d]", a.low, a.high) - - for low := a.low; low <= a.high; low++ { - high := low - for a.reserved(high) && high <= a.high { - high++ - } - - if high > low+1 { - fmt.Fprintf(b, " %d..%d", low, high-1) - } else if high > low { - fmt.Fprintf(b, " %d", high-1) - } - - low = high - } - return b.String() -} - -// Next reserves and returns the next available number out of the range between -// low and high. If no number is available, false is returned. -// -// O(N) worst case runtime where N is allocated, but usually O(1) due to a -// rolling index into the oldest allocation. -func (a *allocator) next() (int, bool) { - wrapped := a.last - - // Find trailing bit - for ; a.last <= a.high; a.last++ { - if a.reserve(a.last) { - return a.last, true - } - } - - // Find preceding free'd pool - a.last = a.low - - for ; a.last < wrapped; a.last++ { - if a.reserve(a.last) { - return a.last, true - } - } - - return 0, false -} - -// reserve claims the bit if it is not already claimed, returning true if -// successfully claimed. -func (a *allocator) reserve(n int) bool { - if a.reserved(n) { - return false - } - a.pool.SetBit(a.pool, n-a.low, allocated) - return true -} - -// reserved returns true if the integer has been allocated -func (a *allocator) reserved(n int) bool { - return a.pool.Bit(n-a.low) == allocated -} - -// release frees the use of the number for another allocation -func (a *allocator) release(n int) { - a.pool.SetBit(a.pool, n-a.low, free) -} diff --git a/vendor/github.com/rabbitmq/amqp091-go/auth.go b/vendor/github.com/rabbitmq/amqp091-go/auth.go deleted file mode 100644 index 0c07bb3..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/auth.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. -// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package amqp091 - -import ( - "bytes" - "fmt" -) - -// Authentication interface provides a means for different SASL authentication -// mechanisms to be used during connection tuning. -type Authentication interface { - Mechanism() string - Response() string -} - -// PlainAuth is a similar to Basic Auth in HTTP. -type PlainAuth struct { - Username string - Password string -} - -// Mechanism returns "PLAIN" -func (auth *PlainAuth) Mechanism() string { - return "PLAIN" -} - -// Response returns the null character delimited encoding for the SASL PLAIN Mechanism. -func (auth *PlainAuth) Response() string { - return fmt.Sprintf("\000%s\000%s", auth.Username, auth.Password) -} - -// AMQPlainAuth is similar to PlainAuth -type AMQPlainAuth struct { - Username string - Password string -} - -// Mechanism returns "AMQPLAIN" -func (auth *AMQPlainAuth) Mechanism() string { - return "AMQPLAIN" -} - -// Response returns an AMQP encoded credentials table, without the field table size. -func (auth *AMQPlainAuth) Response() string { - var buf bytes.Buffer - table := Table{"LOGIN": auth.Username, "PASSWORD": auth.Password} - if err := writeTable(&buf, table); err != nil { - return "" - } - return buf.String()[4:] -} - -// ExternalAuth for RabbitMQ-auth-mechanism-ssl. -type ExternalAuth struct { -} - -// Mechanism returns "EXTERNAL" -func (*ExternalAuth) Mechanism() string { - return "EXTERNAL" -} - -// Response returns an AMQP encoded credentials table, without the field table size. -func (*ExternalAuth) Response() string { - return "\000*\000*" -} - -// Finds the first mechanism preferred by the client that the server supports. -func pickSASLMechanism(client []Authentication, serverMechanisms []string) (auth Authentication, ok bool) { - - for _, auth = range client { - for _, mech := range serverMechanisms { - if auth.Mechanism() == mech { - return auth, true - } - } - } - - return -} diff --git a/vendor/github.com/rabbitmq/amqp091-go/certs.sh b/vendor/github.com/rabbitmq/amqp091-go/certs.sh deleted file mode 100644 index 403e80c..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/certs.sh +++ /dev/null @@ -1,159 +0,0 @@ -#!/bin/sh -# -# Creates the CA, server and client certs to be used by tls_test.go -# http://www.rabbitmq.com/ssl.html -# -# Copy stdout into the const section of tls_test.go or use for RabbitMQ -# -root=$PWD/certs - -if [ -f $root/ca/serial ]; then - echo >&2 "Previous installation found" - echo >&2 "Remove $root/ca and rerun to overwrite" - exit 1 -fi - -mkdir -p $root/ca/private -mkdir -p $root/ca/certs -mkdir -p $root/server -mkdir -p $root/client - -cd $root/ca - -chmod 700 private -touch index.txt -echo 'unique_subject = no' > index.txt.attr -echo '01' > serial -echo >openssl.cnf ' -[ ca ] -default_ca = testca - -[ testca ] -dir = . -certificate = $dir/cacert.pem -database = $dir/index.txt -new_certs_dir = $dir/certs -private_key = $dir/private/cakey.pem -serial = $dir/serial - -default_crl_days = 7 -default_days = 3650 -default_md = sha256 - -policy = testca_policy -x509_extensions = certificate_extensions - -[ testca_policy ] -commonName = supplied -stateOrProvinceName = optional -countryName = optional -emailAddress = optional -organizationName = optional -organizationalUnitName = optional - -[ certificate_extensions ] -basicConstraints = CA:false - -[ req ] -default_bits = 2048 -default_keyfile = ./private/cakey.pem -default_md = sha256 -prompt = yes -distinguished_name = root_ca_distinguished_name -x509_extensions = root_ca_extensions - -[ root_ca_distinguished_name ] -commonName = hostname - -[ root_ca_extensions ] -basicConstraints = CA:true -keyUsage = keyCertSign, cRLSign - -[ client_ca_extensions ] -basicConstraints = CA:false -keyUsage = digitalSignature -extendedKeyUsage = 1.3.6.1.5.5.7.3.2 - -[ server_ca_extensions ] -basicConstraints = CA:false -keyUsage = keyEncipherment -extendedKeyUsage = 1.3.6.1.5.5.7.3.1 -subjectAltName = @alt_names - -[ alt_names ] -IP.1 = 127.0.0.1 -' - -openssl req \ - -x509 \ - -nodes \ - -config openssl.cnf \ - -newkey rsa:2048 \ - -days 3650 \ - -subj "/CN=MyTestCA/" \ - -out cacert.pem \ - -outform PEM - -openssl x509 \ - -in cacert.pem \ - -out cacert.cer \ - -outform DER - -openssl genrsa -out $root/server/key.pem 2048 -openssl genrsa -out $root/client/key.pem 2048 - -openssl req \ - -new \ - -nodes \ - -config openssl.cnf \ - -subj "/CN=127.0.0.1/O=server/" \ - -key $root/server/key.pem \ - -out $root/server/req.pem \ - -outform PEM - -openssl req \ - -new \ - -nodes \ - -config openssl.cnf \ - -subj "/CN=127.0.0.1/O=client/" \ - -key $root/client/key.pem \ - -out $root/client/req.pem \ - -outform PEM - -openssl ca \ - -config openssl.cnf \ - -in $root/server/req.pem \ - -out $root/server/cert.pem \ - -notext \ - -batch \ - -extensions server_ca_extensions - -openssl ca \ - -config openssl.cnf \ - -in $root/client/req.pem \ - -out $root/client/cert.pem \ - -notext \ - -batch \ - -extensions client_ca_extensions - -cat <<-END -const caCert = \` -`cat $root/ca/cacert.pem` -\` - -const serverCert = \` -`cat $root/server/cert.pem` -\` - -const serverKey = \` -`cat $root/server/key.pem` -\` - -const clientCert = \` -`cat $root/client/cert.pem` -\` - -const clientKey = \` -`cat $root/client/key.pem` -\` -END diff --git a/vendor/github.com/rabbitmq/amqp091-go/change_version.sh b/vendor/github.com/rabbitmq/amqp091-go/change_version.sh deleted file mode 100644 index ff8e369..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/change_version.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -echo $1 > VERSION -sed -i -e "s/.*buildVersion = \"*.*/buildVersion = \"$1\"/" ./connection.go -go fmt ./... diff --git a/vendor/github.com/rabbitmq/amqp091-go/channel.go b/vendor/github.com/rabbitmq/amqp091-go/channel.go deleted file mode 100644 index ae6f2d1..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/channel.go +++ /dev/null @@ -1,1709 +0,0 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. -// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package amqp091 - -import ( - "context" - "errors" - "reflect" - "sync" - "sync/atomic" -) - -// 0 1 3 7 size+7 size+8 -// +------+---------+-------------+ +------------+ +-----------+ -// | type | channel | size | | payload | | frame-end | -// +------+---------+-------------+ +------------+ +-----------+ -// -// octet short long size octets octet -const frameHeaderSize = 1 + 2 + 4 + 1 - -/* -Channel represents an AMQP channel. Used as a context for valid message -exchange. Errors on methods with this Channel as a receiver means this channel -should be discarded and a new channel established. -*/ -type Channel struct { - destructor sync.Once - m sync.Mutex // struct field mutex - confirmM sync.Mutex // publisher confirms state mutex - notifyM sync.RWMutex - - connection *Connection - - rpc chan message - consumers *consumers - - id uint16 - - // closed is set to 1 when the channel has been closed - see Channel.send() - closed int32 - - // true when we will never notify again - noNotify bool - - // Channel and Connection exceptions will be broadcast on these listeners. - closes []chan *Error - - // Listeners for active=true flow control. When true is sent to a listener, - // publishing should pause until false is sent to listeners. - flows []chan bool - - // Listeners for returned publishings for unroutable messages on mandatory - // publishings or undeliverable messages on immediate publishings. - returns []chan Return - - // Listeners for when the server notifies the client that - // a consumer has been cancelled. - cancels []chan string - - // Allocated when in confirm mode in order to track publish counter and order confirms - confirms *confirms - confirming bool - - // Selects on any errors from shutdown during RPC - errors chan *Error - - // State machine that manages frame order, must only be mutated by the connection - recv func(*Channel, frame) - - // Current state for frame re-assembly, only mutated from recv - message messageWithContent - header *headerFrame - body []byte -} - -// Constructs a new channel with the given framing rules -func newChannel(c *Connection, id uint16) *Channel { - return &Channel{ - connection: c, - id: id, - rpc: make(chan message), - consumers: makeConsumers(), - confirms: newConfirms(), - recv: (*Channel).recvMethod, - errors: make(chan *Error, 1), - } -} - -// Signal that from now on, Channel.send() should call Channel.sendClosed() -func (ch *Channel) setClosed() { - atomic.StoreInt32(&ch.closed, 1) -} - -// shutdown is called by Connection after the channel has been removed from the -// connection registry. -func (ch *Channel) shutdown(e *Error) { - ch.setClosed() - - ch.destructor.Do(func() { - ch.m.Lock() - defer ch.m.Unlock() - - // Grab an exclusive lock for the notify channels - ch.notifyM.Lock() - defer ch.notifyM.Unlock() - - // Broadcast abnormal shutdown - if e != nil { - for _, c := range ch.closes { - c <- e - } - // Notify RPC if we're selecting - ch.errors <- e - } - - ch.consumers.close() - - for _, c := range ch.closes { - close(c) - } - - for _, c := range ch.flows { - close(c) - } - - for _, c := range ch.returns { - close(c) - } - - for _, c := range ch.cancels { - close(c) - } - - // Set the slices to nil to prevent the dispatch() range from sending on - // the now closed channels after we release the notifyM mutex - ch.flows = nil - ch.closes = nil - ch.returns = nil - ch.cancels = nil - - if ch.confirms != nil { - ch.confirms.Close() - } - - close(ch.errors) - ch.noNotify = true - }) -} - -// send calls Channel.sendOpen() during normal operation. -// -// After the channel has been closed, send calls Channel.sendClosed(), ensuring -// only 'channel.close' is sent to the server. -func (ch *Channel) send(msg message) (err error) { - // If the channel is closed, use Channel.sendClosed() - if ch.IsClosed() { - return ch.sendClosed(msg) - } - - return ch.sendOpen(msg) -} - -func (ch *Channel) open() error { - return ch.call(&channelOpen{}, &channelOpenOk{}) -} - -// Performs a request/response call for when the message is not NoWait and is -// specified as Synchronous. -func (ch *Channel) call(req message, res ...message) error { - if err := ch.send(req); err != nil { - return err - } - - if req.wait() { - select { - case e, ok := <-ch.errors: - if ok { - return e - } - return ErrClosed - - case msg := <-ch.rpc: - if msg != nil { - for _, try := range res { - if reflect.TypeOf(msg) == reflect.TypeOf(try) { - // *res = *msg - vres := reflect.ValueOf(try).Elem() - vmsg := reflect.ValueOf(msg).Elem() - vres.Set(vmsg) - return nil - } - } - return ErrCommandInvalid - } - // RPC channel has been closed without an error, likely due to a hard - // error on the Connection. This indicates we have already been - // shutdown and if were waiting, will have returned from the errors chan. - return ErrClosed - } - } - - return nil -} - -func (ch *Channel) sendClosed(msg message) (err error) { - // After a 'channel.close' is sent or received the only valid response is - // channel.close-ok - if _, ok := msg.(*channelCloseOk); ok { - return ch.connection.send(&methodFrame{ - ChannelId: ch.id, - Method: msg, - }) - } - - return ErrClosed -} - -func (ch *Channel) sendOpen(msg message) (err error) { - if content, ok := msg.(messageWithContent); ok { - props, body := content.getContent() - class, _ := content.id() - - // catch client max frame size==0 and server max frame size==0 - // set size to length of what we're trying to publish - var size int - if ch.connection.Config.FrameSize > 0 { - size = ch.connection.Config.FrameSize - frameHeaderSize - } else { - size = len(body) - } - - // If the channel is closed, use Channel.sendClosed() - if ch.IsClosed() { - return ch.sendClosed(msg) - } - - // Flush the buffer only after all the Frames that comprise the Message - // have been written to maximise benefits of using a buffered writer. - defer func() { - if endError := ch.connection.endSendUnflushed(); endError != nil { - if err == nil { - err = endError - } - } - }() - - // We use sendUnflushed() in this method as sending the message requires - // sending multiple Frames (methodFrame, headerFrame, N x bodyFrame). - // Flushing after each Frame is inefficient, as it negates much of the - // benefit of using a buffered writer and results in more syscalls than - // necessary. Flushing buffers after every frame can have a significant - // performance impact when sending (e.g. basicPublish) small messages, - // so sendUnflushed() performs an *Unflushed* write, but is otherwise - // equivalent to the send() method. We later use the separate flush - // method to explicitly flush the buffer after all Frames are written. - if err = ch.connection.sendUnflushed(&methodFrame{ - ChannelId: ch.id, - Method: content, - }); err != nil { - return - } - - if err = ch.connection.sendUnflushed(&headerFrame{ - ChannelId: ch.id, - ClassId: class, - Size: uint64(len(body)), - Properties: props, - }); err != nil { - return - } - - // chunk body into size (max frame size - frame header size) - for i, j := 0, size; i < len(body); i, j = j, j+size { - if j > len(body) { - j = len(body) - } - - if err = ch.connection.sendUnflushed(&bodyFrame{ - ChannelId: ch.id, - Body: body[i:j], - }); err != nil { - return - } - } - } else { - // If the channel is closed, use Channel.sendClosed() - if ch.IsClosed() { - return ch.sendClosed(msg) - } - - err = ch.connection.send(&methodFrame{ - ChannelId: ch.id, - Method: msg, - }) - } - - return -} - -// Eventually called via the state machine from the connection's reader -// goroutine, so assumes serialized access. -func (ch *Channel) dispatch(msg message) { - switch m := msg.(type) { - case *channelClose: - // Note: channel state is set to closed immedately after the message is - // decoded by the Connection - - // lock before sending connection.close-ok - // to avoid unexpected interleaving with basic.publish frames if - // publishing is happening concurrently - ch.m.Lock() - if err := ch.send(&channelCloseOk{}); err != nil { - Logger.Printf("error sending channelCloseOk, channel id: %d error: %+v", ch.id, err) - } - ch.m.Unlock() - ch.connection.closeChannel(ch, newError(m.ReplyCode, m.ReplyText)) - - case *channelFlow: - ch.notifyM.RLock() - for _, c := range ch.flows { - c <- m.Active - } - ch.notifyM.RUnlock() - if err := ch.send(&channelFlowOk{Active: m.Active}); err != nil { - Logger.Printf("error sending channelFlowOk, channel id: %d error: %+v", ch.id, err) - } - - case *basicCancel: - ch.notifyM.RLock() - for _, c := range ch.cancels { - c <- m.ConsumerTag - } - ch.notifyM.RUnlock() - ch.consumers.cancel(m.ConsumerTag) - - case *basicReturn: - ret := newReturn(*m) - ch.notifyM.RLock() - for _, c := range ch.returns { - c <- *ret - } - ch.notifyM.RUnlock() - - case *basicAck: - if ch.confirming { - if m.Multiple { - ch.confirms.Multiple(Confirmation{m.DeliveryTag, true}) - } else { - ch.confirms.One(Confirmation{m.DeliveryTag, true}) - } - } - - case *basicNack: - if ch.confirming { - if m.Multiple { - ch.confirms.Multiple(Confirmation{m.DeliveryTag, false}) - } else { - ch.confirms.One(Confirmation{m.DeliveryTag, false}) - } - } - - case *basicDeliver: - ch.consumers.send(m.ConsumerTag, newDelivery(ch, m)) - // TODO log failed consumer and close channel, this can happen when - // deliveries are in flight and a no-wait cancel has happened - - default: - ch.rpc <- msg - } -} - -func (ch *Channel) transition(f func(*Channel, frame)) { - ch.recv = f -} - -func (ch *Channel) recvMethod(f frame) { - switch frame := f.(type) { - case *methodFrame: - if msg, ok := frame.Method.(messageWithContent); ok { - ch.body = make([]byte, 0) - ch.message = msg - ch.transition((*Channel).recvHeader) - return - } - - ch.dispatch(frame.Method) // termination state - ch.transition((*Channel).recvMethod) - - case *headerFrame: - // drop - ch.transition((*Channel).recvMethod) - - case *bodyFrame: - // drop - ch.transition((*Channel).recvMethod) - - default: - panic("unexpected frame type") - } -} - -func (ch *Channel) recvHeader(f frame) { - switch frame := f.(type) { - case *methodFrame: - // interrupt content and handle method - ch.recvMethod(f) - - case *headerFrame: - // start collecting if we expect body frames - ch.header = frame - - if frame.Size == 0 { - ch.message.setContent(ch.header.Properties, ch.body) - ch.dispatch(ch.message) // termination state - ch.transition((*Channel).recvMethod) - return - } - ch.transition((*Channel).recvContent) - - case *bodyFrame: - // drop and reset - ch.transition((*Channel).recvMethod) - - default: - panic("unexpected frame type") - } -} - -// state after method + header and before the length -// defined by the header has been reached -func (ch *Channel) recvContent(f frame) { - switch frame := f.(type) { - case *methodFrame: - // interrupt content and handle method - ch.recvMethod(f) - - case *headerFrame: - // drop and reset - ch.transition((*Channel).recvMethod) - - case *bodyFrame: - if cap(ch.body) == 0 { - ch.body = make([]byte, 0, ch.header.Size) - } - ch.body = append(ch.body, frame.Body...) - - if uint64(len(ch.body)) >= ch.header.Size { - ch.message.setContent(ch.header.Properties, ch.body) - ch.dispatch(ch.message) // termination state - ch.transition((*Channel).recvMethod) - return - } - - ch.transition((*Channel).recvContent) - - default: - panic("unexpected frame type") - } -} - -/* -Close initiate a clean channel closure by sending a close message with the error -code set to '200'. - -It is safe to call this method multiple times. -*/ -func (ch *Channel) Close() error { - defer ch.connection.closeChannel(ch, nil) - return ch.call( - &channelClose{ReplyCode: replySuccess}, - &channelCloseOk{}, - ) -} - -// IsClosed returns true if the channel is marked as closed, otherwise false -// is returned. -func (ch *Channel) IsClosed() bool { - return atomic.LoadInt32(&ch.closed) == 1 -} - -/* -NotifyClose registers a listener for when the server sends a channel or -connection exception in the form of a Connection.Close or Channel.Close method. -Connection exceptions will be broadcast to all open channels and all channels -will be closed, where channel exceptions will only be broadcast to listeners to -this channel. - -The chan provided will be closed when the Channel is closed and on a -graceful close, no error will be sent. - -In case of a non graceful close the error will be notified synchronously by the library -so that it will be necessary to consume the Channel from the caller in order to avoid deadlocks -*/ -func (ch *Channel) NotifyClose(c chan *Error) chan *Error { - ch.notifyM.Lock() - defer ch.notifyM.Unlock() - - if ch.noNotify { - close(c) - } else { - ch.closes = append(ch.closes, c) - } - - return c -} - -/* -NotifyFlow registers a listener for basic.flow methods sent by the server. -When `false` is sent on one of the listener channels, all publishers should -pause until a `true` is sent. - -The server may ask the producer to pause or restart the flow of Publishings -sent by on a channel. This is a simple flow-control mechanism that a server can -use to avoid overflowing its queues or otherwise finding itself receiving more -messages than it can process. Note that this method is not intended for window -control. It does not affect contents returned by basic.get-ok methods. - -When a new channel is opened, it is active (flow is active). Some -applications assume that channels are inactive until started. To emulate -this behavior a client MAY open the channel, then pause it. - -Publishers should respond to a flow messages as rapidly as possible and the -server may disconnect over producing channels that do not respect these -messages. - -basic.flow-ok methods will always be returned to the server regardless of -the number of listeners there are. - -To control the flow of deliveries from the server, use the Channel.Flow() -method instead. - -Note: RabbitMQ will rather use TCP pushback on the network connection instead -of sending basic.flow. This means that if a single channel is producing too -much on the same connection, all channels using that connection will suffer, -including acknowledgments from deliveries. Use different Connections if you -desire to interleave consumers and producers in the same process to avoid your -basic.ack messages from getting rate limited with your basic.publish messages. -*/ -func (ch *Channel) NotifyFlow(c chan bool) chan bool { - ch.notifyM.Lock() - defer ch.notifyM.Unlock() - - if ch.noNotify { - close(c) - } else { - ch.flows = append(ch.flows, c) - } - - return c -} - -/* -NotifyReturn registers a listener for basic.return methods. These can be sent -from the server when a publish is undeliverable either from the mandatory or -immediate flags. - -A return struct has a copy of the Publishing along with some error -information about why the publishing failed. -*/ -func (ch *Channel) NotifyReturn(c chan Return) chan Return { - ch.notifyM.Lock() - defer ch.notifyM.Unlock() - - if ch.noNotify { - close(c) - } else { - ch.returns = append(ch.returns, c) - } - - return c -} - -/* -NotifyCancel registers a listener for basic.cancel methods. These can be sent -from the server when a queue is deleted or when consuming from a mirrored queue -where the master has just failed (and was moved to another node). - -The subscription tag is returned to the listener. -*/ -func (ch *Channel) NotifyCancel(c chan string) chan string { - ch.notifyM.Lock() - defer ch.notifyM.Unlock() - - if ch.noNotify { - close(c) - } else { - ch.cancels = append(ch.cancels, c) - } - - return c -} - -/* -NotifyConfirm calls NotifyPublish and starts a goroutine sending -ordered Ack and Nack DeliveryTag to the respective channels. - -For strict ordering, use NotifyPublish instead. -*/ -func (ch *Channel) NotifyConfirm(ack, nack chan uint64) (chan uint64, chan uint64) { - confirms := ch.NotifyPublish(make(chan Confirmation, cap(ack)+cap(nack))) - - go func() { - for c := range confirms { - if c.Ack { - ack <- c.DeliveryTag - } else { - nack <- c.DeliveryTag - } - } - close(ack) - if nack != ack { - close(nack) - } - }() - - return ack, nack -} - -/* -NotifyPublish registers a listener for reliable publishing. Receives from this -chan for every publish after Channel.Confirm will be in order starting with -DeliveryTag 1. - -There will be one and only one Confirmation Publishing starting with the -delivery tag of 1 and progressing sequentially until the total number of -Publishings have been seen by the server. - -Acknowledgments will be received in the order of delivery from the -NotifyPublish channels even if the server acknowledges them out of order. - -The listener chan will be closed when the Channel is closed. - -The capacity of the chan Confirmation must be at least as large as the -number of outstanding publishings. Not having enough buffered chans will -create a deadlock if you attempt to perform other operations on the Connection -or Channel while confirms are in-flight. - -It's advisable to wait for all Confirmations to arrive before calling -Channel.Close() or Connection.Close(). - -It is also advisable for the caller to consume from the channel returned till it is closed -to avoid possible deadlocks -*/ -func (ch *Channel) NotifyPublish(confirm chan Confirmation) chan Confirmation { - ch.notifyM.Lock() - defer ch.notifyM.Unlock() - - if ch.noNotify { - close(confirm) - } else { - ch.confirms.Listen(confirm) - } - - return confirm -} - -/* -Qos controls how many messages or how many bytes the server will try to keep on -the network for consumers before receiving delivery acks. The intent of Qos is -to make sure the network buffers stay full between the server and client. - -With a prefetch count greater than zero, the server will deliver that many -messages to consumers before acknowledgments are received. The server ignores -this option when consumers are started with noAck because no acknowledgments -are expected or sent. - -With a prefetch size greater than zero, the server will try to keep at least -that many bytes of deliveries flushed to the network before receiving -acknowledgments from the consumers. This option is ignored when consumers are -started with noAck. - -When global is true, these Qos settings apply to all existing and future -consumers on all channels on the same connection. When false, the Channel.Qos -settings will apply to all existing and future consumers on this channel. - -Please see the RabbitMQ Consumer Prefetch documentation for an explanation of -how the global flag is implemented in RabbitMQ, as it differs from the -AMQP 0.9.1 specification in that global Qos settings are limited in scope to -channels, not connections (https://www.rabbitmq.com/consumer-prefetch.html). - -To get round-robin behavior between consumers consuming from the same queue on -different connections, set the prefetch count to 1, and the next available -message on the server will be delivered to the next available consumer. - -If your consumer work time is reasonably consistent and not much greater -than two times your network round trip time, you will see significant -throughput improvements starting with a prefetch count of 2 or slightly -greater as described by benchmarks on RabbitMQ. - -http://www.rabbitmq.com/blog/2012/04/25/rabbitmq-performance-measurements-part-2/ -*/ -func (ch *Channel) Qos(prefetchCount, prefetchSize int, global bool) error { - return ch.call( - &basicQos{ - PrefetchCount: uint16(prefetchCount), - PrefetchSize: uint32(prefetchSize), - Global: global, - }, - &basicQosOk{}, - ) -} - -/* -Cancel stops deliveries to the consumer chan established in Channel.Consume and -identified by consumer. - -Only use this method to cleanly stop receiving deliveries from the server and -cleanly shut down the consumer chan identified by this tag. Using this method -and waiting for remaining messages to flush from the consumer chan will ensure -all messages received on the network will be delivered to the receiver of your -consumer chan. - -Continue consuming from the chan Delivery provided by Channel.Consume until the -chan closes. - -When noWait is true, do not wait for the server to acknowledge the cancel. -Only use this when you are certain there are no deliveries in flight that -require an acknowledgment, otherwise they will arrive and be dropped in the -client without an ack, and will not be redelivered to other consumers. -*/ -func (ch *Channel) Cancel(consumer string, noWait bool) error { - req := &basicCancel{ - ConsumerTag: consumer, - NoWait: noWait, - } - res := &basicCancelOk{} - - if err := ch.call(req, res); err != nil { - return err - } - - if req.wait() { - ch.consumers.cancel(res.ConsumerTag) - } else { - // Potentially could drop deliveries in flight - ch.consumers.cancel(consumer) - } - - return nil -} - -/* -QueueDeclare declares a queue to hold messages and deliver to consumers. -Declaring creates a queue if it doesn't already exist, or ensures that an -existing queue matches the same parameters. - -Every queue declared gets a default binding to the empty exchange "" which has -the type "direct" with the routing key matching the queue's name. With this -default binding, it is possible to publish messages that route directly to -this queue by publishing to "" with the routing key of the queue name. - - QueueDeclare("alerts", true, false, false, false, nil) - Publish("", "alerts", false, false, Publishing{Body: []byte("...")}) - - Delivery Exchange Key Queue - ----------------------------------------------- - key: alerts -> "" -> alerts -> alerts - -The queue name may be empty, in which case the server will generate a unique name -which will be returned in the Name field of Queue struct. - -Durable and Non-Auto-Deleted queues will survive server restarts and remain -when there are no remaining consumers or bindings. Persistent publishings will -be restored in this queue on server restart. These queues are only able to be -bound to durable exchanges. - -Non-Durable and Auto-Deleted queues will not be redeclared on server restart -and will be deleted by the server after a short time when the last consumer is -canceled or the last consumer's channel is closed. Queues with this lifetime -can also be deleted normally with QueueDelete. These durable queues can only -be bound to non-durable exchanges. - -Non-Durable and Non-Auto-Deleted queues will remain declared as long as the -server is running regardless of how many consumers. This lifetime is useful -for temporary topologies that may have long delays between consumer activity. -These queues can only be bound to non-durable exchanges. - -Durable and Auto-Deleted queues will be restored on server restart, but without -active consumers will not survive and be removed. This Lifetime is unlikely -to be useful. - -Exclusive queues are only accessible by the connection that declares them and -will be deleted when the connection closes. Channels on other connections -will receive an error when attempting to declare, bind, consume, purge or -delete a queue with the same name. - -When noWait is true, the queue will assume to be declared on the server. A -channel exception will arrive if the conditions are met for existing queues -or attempting to modify an existing queue from a different connection. - -When the error return value is not nil, you can assume the queue could not be -declared with these parameters, and the channel will be closed. -*/ -func (ch *Channel) QueueDeclare(name string, durable, autoDelete, exclusive, noWait bool, args Table) (Queue, error) { - if err := args.Validate(); err != nil { - return Queue{}, err - } - - req := &queueDeclare{ - Queue: name, - Passive: false, - Durable: durable, - AutoDelete: autoDelete, - Exclusive: exclusive, - NoWait: noWait, - Arguments: args, - } - res := &queueDeclareOk{} - - if err := ch.call(req, res); err != nil { - return Queue{}, err - } - - if req.wait() { - return Queue{ - Name: res.Queue, - Messages: int(res.MessageCount), - Consumers: int(res.ConsumerCount), - }, nil - } - - return Queue{Name: name}, nil -} - -/* -QueueDeclarePassive is functionally and parametrically equivalent to -QueueDeclare, except that it sets the "passive" attribute to true. A passive -queue is assumed by RabbitMQ to already exist, and attempting to connect to a -non-existent queue will cause RabbitMQ to throw an exception. This function -can be used to test for the existence of a queue. -*/ -func (ch *Channel) QueueDeclarePassive(name string, durable, autoDelete, exclusive, noWait bool, args Table) (Queue, error) { - if err := args.Validate(); err != nil { - return Queue{}, err - } - - req := &queueDeclare{ - Queue: name, - Passive: true, - Durable: durable, - AutoDelete: autoDelete, - Exclusive: exclusive, - NoWait: noWait, - Arguments: args, - } - res := &queueDeclareOk{} - - if err := ch.call(req, res); err != nil { - return Queue{}, err - } - - if req.wait() { - return Queue{ - Name: res.Queue, - Messages: int(res.MessageCount), - Consumers: int(res.ConsumerCount), - }, nil - } - - return Queue{Name: name}, nil -} - -/* -QueueInspect passively declares a queue by name to inspect the current message -count and consumer count. - -Use this method to check how many messages ready for delivery reside in the queue, -how many consumers are receiving deliveries, and whether a queue by this -name already exists. - -If the queue by this name exists, use Channel.QueueDeclare check if it is -declared with specific parameters. - -If a queue by this name does not exist, an error will be returned and the -channel will be closed. - -Deprecated: Use QueueDeclare with "Passive: true" instead. -*/ -func (ch *Channel) QueueInspect(name string) (Queue, error) { - req := &queueDeclare{ - Queue: name, - Passive: true, - } - res := &queueDeclareOk{} - - err := ch.call(req, res) - - state := Queue{ - Name: name, - Messages: int(res.MessageCount), - Consumers: int(res.ConsumerCount), - } - - return state, err -} - -/* -QueueBind binds an exchange to a queue so that publishings to the exchange will -be routed to the queue when the publishing routing key matches the binding -routing key. - - QueueBind("pagers", "alert", "log", false, nil) - QueueBind("emails", "info", "log", false, nil) - - Delivery Exchange Key Queue - ----------------------------------------------- - key: alert --> log ----> alert --> pagers - key: info ---> log ----> info ---> emails - key: debug --> log (none) (dropped) - -If a binding with the same key and arguments already exists between the -exchange and queue, the attempt to rebind will be ignored and the existing -binding will be retained. - -In the case that multiple bindings may cause the message to be routed to the -same queue, the server will only route the publishing once. This is possible -with topic exchanges. - - QueueBind("pagers", "alert", "amq.topic", false, nil) - QueueBind("emails", "info", "amq.topic", false, nil) - QueueBind("emails", "#", "amq.topic", false, nil) // match everything - - Delivery Exchange Key Queue - ----------------------------------------------- - key: alert --> amq.topic ----> alert --> pagers - key: info ---> amq.topic ----> # ------> emails - \---> info ---/ - key: debug --> amq.topic ----> # ------> emails - -It is only possible to bind a durable queue to a durable exchange regardless of -whether the queue or exchange is auto-deleted. Bindings between durable queues -and exchanges will also be restored on server restart. - -If the binding could not complete, an error will be returned and the channel -will be closed. - -When noWait is false and the queue could not be bound, the channel will be -closed with an error. -*/ -func (ch *Channel) QueueBind(name, key, exchange string, noWait bool, args Table) error { - if err := args.Validate(); err != nil { - return err - } - - return ch.call( - &queueBind{ - Queue: name, - Exchange: exchange, - RoutingKey: key, - NoWait: noWait, - Arguments: args, - }, - &queueBindOk{}, - ) -} - -/* -QueueUnbind removes a binding between an exchange and queue matching the key and -arguments. - -It is possible to send and empty string for the exchange name which means to -unbind the queue from the default exchange. -*/ -func (ch *Channel) QueueUnbind(name, key, exchange string, args Table) error { - if err := args.Validate(); err != nil { - return err - } - - return ch.call( - &queueUnbind{ - Queue: name, - Exchange: exchange, - RoutingKey: key, - Arguments: args, - }, - &queueUnbindOk{}, - ) -} - -/* -QueuePurge removes all messages from the named queue which are not waiting to -be acknowledged. Messages that have been delivered but have not yet been -acknowledged will not be removed. - -When successful, returns the number of messages purged. - -If noWait is true, do not wait for the server response and the number of -messages purged will not be meaningful. -*/ -func (ch *Channel) QueuePurge(name string, noWait bool) (int, error) { - req := &queuePurge{ - Queue: name, - NoWait: noWait, - } - res := &queuePurgeOk{} - - err := ch.call(req, res) - - return int(res.MessageCount), err -} - -/* -QueueDelete removes the queue from the server including all bindings then -purges the messages based on server configuration, returning the number of -messages purged. - -When ifUnused is true, the queue will not be deleted if there are any -consumers on the queue. If there are consumers, an error will be returned and -the channel will be closed. - -When ifEmpty is true, the queue will not be deleted if there are any messages -remaining on the queue. If there are messages, an error will be returned and -the channel will be closed. - -When noWait is true, the queue will be deleted without waiting for a response -from the server. The purged message count will not be meaningful. If the queue -could not be deleted, a channel exception will be raised and the channel will -be closed. -*/ -func (ch *Channel) QueueDelete(name string, ifUnused, ifEmpty, noWait bool) (int, error) { - req := &queueDelete{ - Queue: name, - IfUnused: ifUnused, - IfEmpty: ifEmpty, - NoWait: noWait, - } - res := &queueDeleteOk{} - - err := ch.call(req, res) - - return int(res.MessageCount), err -} - -/* -Consume immediately starts delivering queued messages. - -Begin receiving on the returned chan Delivery before any other operation on the -Connection or Channel. - -Continues deliveries to the returned chan Delivery until Channel.Cancel, -Connection.Close, Channel.Close, or an AMQP exception occurs. Consumers must -range over the chan to ensure all deliveries are received. Unreceived -deliveries will block all methods on the same connection. - -All deliveries in AMQP must be acknowledged. It is expected of the consumer to -call Delivery.Ack after it has successfully processed the delivery. If the -consumer is cancelled or the channel or connection is closed any unacknowledged -deliveries will be requeued at the end of the same queue. - -The consumer is identified by a string that is unique and scoped for all -consumers on this channel. If you wish to eventually cancel the consumer, use -the same non-empty identifier in Channel.Cancel. An empty string will cause -the library to generate a unique identity. The consumer identity will be -included in every Delivery in the ConsumerTag field - -When autoAck (also known as noAck) is true, the server will acknowledge -deliveries to this consumer prior to writing the delivery to the network. When -autoAck is true, the consumer should not call Delivery.Ack. Automatically -acknowledging deliveries means that some deliveries may get lost if the -consumer is unable to process them after the server delivers them. -See http://www.rabbitmq.com/confirms.html for more details. - -When exclusive is true, the server will ensure that this is the sole consumer -from this queue. When exclusive is false, the server will fairly distribute -deliveries across multiple consumers. - -The noLocal flag is not supported by RabbitMQ. - -It's advisable to use separate connections for -Channel.Publish and Channel.Consume so not to have TCP pushback on publishing -affect the ability to consume messages, so this parameter is here mostly for -completeness. - -When noWait is true, do not wait for the server to confirm the request and -immediately begin deliveries. If it is not possible to consume, a channel -exception will be raised and the channel will be closed. - -Optional arguments can be provided that have specific semantics for the queue -or server. - -Inflight messages, limited by Channel.Qos will be buffered until received from -the returned chan. - -When the Channel or Connection is closed, all buffered and inflight messages will -be dropped. - -When the consumer tag is cancelled, all inflight messages will be delivered until -the returned chan is closed. -*/ -func (ch *Channel) Consume(queue, consumer string, autoAck, exclusive, noLocal, noWait bool, args Table) (<-chan Delivery, error) { - // When we return from ch.call, there may be a delivery already for the - // consumer that hasn't been added to the consumer hash yet. Because of - // this, we never rely on the server picking a consumer tag for us. - - if err := args.Validate(); err != nil { - return nil, err - } - - if consumer == "" { - consumer = uniqueConsumerTag() - } - - req := &basicConsume{ - Queue: queue, - ConsumerTag: consumer, - NoLocal: noLocal, - NoAck: autoAck, - Exclusive: exclusive, - NoWait: noWait, - Arguments: args, - } - res := &basicConsumeOk{} - - deliveries := make(chan Delivery) - - ch.consumers.add(consumer, deliveries) - - if err := ch.call(req, res); err != nil { - ch.consumers.cancel(consumer) - return nil, err - } - - return deliveries, nil -} - -/* -ExchangeDeclare declares an exchange on the server. If the exchange does not -already exist, the server will create it. If the exchange exists, the server -verifies that it is of the provided type, durability and auto-delete flags. - -Errors returned from this method will close the channel. - -Exchange names starting with "amq." are reserved for pre-declared and -standardized exchanges. The client MAY declare an exchange starting with -"amq." if the passive option is set, or the exchange already exists. Names can -consist of a non-empty sequence of letters, digits, hyphen, underscore, -period, or colon. - -Each exchange belongs to one of a set of exchange kinds/types implemented by -the server. The exchange types define the functionality of the exchange - i.e. -how messages are routed through it. Once an exchange is declared, its type -cannot be changed. The common types are "direct", "fanout", "topic" and -"headers". - -Durable and Non-Auto-Deleted exchanges will survive server restarts and remain -declared when there are no remaining bindings. This is the best lifetime for -long-lived exchange configurations like stable routes and default exchanges. - -Non-Durable and Auto-Deleted exchanges will be deleted when there are no -remaining bindings and not restored on server restart. This lifetime is -useful for temporary topologies that should not pollute the virtual host on -failure or after the consumers have completed. - -Non-Durable and Non-Auto-deleted exchanges will remain as long as the server is -running including when there are no remaining bindings. This is useful for -temporary topologies that may have long delays between bindings. - -Durable and Auto-Deleted exchanges will survive server restarts and will be -removed before and after server restarts when there are no remaining bindings. -These exchanges are useful for robust temporary topologies or when you require -binding durable queues to auto-deleted exchanges. - -Note: RabbitMQ declares the default exchange types like 'amq.fanout' as -durable, so queues that bind to these pre-declared exchanges must also be -durable. - -Exchanges declared as `internal` do not accept accept publishings. Internal -exchanges are useful when you wish to implement inter-exchange topologies -that should not be exposed to users of the broker. - -When noWait is true, declare without waiting for a confirmation from the server. -The channel may be closed as a result of an error. Add a NotifyClose listener -to respond to any exceptions. - -Optional amqp.Table of arguments that are specific to the server's implementation of -the exchange can be sent for exchange types that require extra parameters. -*/ -func (ch *Channel) ExchangeDeclare(name, kind string, durable, autoDelete, internal, noWait bool, args Table) error { - if err := args.Validate(); err != nil { - return err - } - - return ch.call( - &exchangeDeclare{ - Exchange: name, - Type: kind, - Passive: false, - Durable: durable, - AutoDelete: autoDelete, - Internal: internal, - NoWait: noWait, - Arguments: args, - }, - &exchangeDeclareOk{}, - ) -} - -/* -ExchangeDeclarePassive is functionally and parametrically equivalent to -ExchangeDeclare, except that it sets the "passive" attribute to true. A passive -exchange is assumed by RabbitMQ to already exist, and attempting to connect to a -non-existent exchange will cause RabbitMQ to throw an exception. This function -can be used to detect the existence of an exchange. -*/ -func (ch *Channel) ExchangeDeclarePassive(name, kind string, durable, autoDelete, internal, noWait bool, args Table) error { - if err := args.Validate(); err != nil { - return err - } - - return ch.call( - &exchangeDeclare{ - Exchange: name, - Type: kind, - Passive: true, - Durable: durable, - AutoDelete: autoDelete, - Internal: internal, - NoWait: noWait, - Arguments: args, - }, - &exchangeDeclareOk{}, - ) -} - -/* -ExchangeDelete removes the named exchange from the server. When an exchange is -deleted all queue bindings on the exchange are also deleted. If this exchange -does not exist, the channel will be closed with an error. - -When ifUnused is true, the server will only delete the exchange if it has no queue -bindings. If the exchange has queue bindings the server does not delete it -but close the channel with an exception instead. Set this to true if you are -not the sole owner of the exchange. - -When noWait is true, do not wait for a server confirmation that the exchange has -been deleted. Failing to delete the channel could close the channel. Add a -NotifyClose listener to respond to these channel exceptions. -*/ -func (ch *Channel) ExchangeDelete(name string, ifUnused, noWait bool) error { - return ch.call( - &exchangeDelete{ - Exchange: name, - IfUnused: ifUnused, - NoWait: noWait, - }, - &exchangeDeleteOk{}, - ) -} - -/* -ExchangeBind binds an exchange to another exchange to create inter-exchange -routing topologies on the server. This can decouple the private topology and -routing exchanges from exchanges intended solely for publishing endpoints. - -Binding two exchanges with identical arguments will not create duplicate -bindings. - -Binding one exchange to another with multiple bindings will only deliver a -message once. For example if you bind your exchange to `amq.fanout` with two -different binding keys, only a single message will be delivered to your -exchange even though multiple bindings will match. - -Given a message delivered to the source exchange, the message will be forwarded -to the destination exchange when the routing key is matched. - - ExchangeBind("sell", "MSFT", "trade", false, nil) - ExchangeBind("buy", "AAPL", "trade", false, nil) - - Delivery Source Key Destination - example exchange exchange - ----------------------------------------------- - key: AAPL --> trade ----> MSFT sell - \---> AAPL --> buy - -When noWait is true, do not wait for the server to confirm the binding. If any -error occurs the channel will be closed. Add a listener to NotifyClose to -handle these errors. - -Optional arguments specific to the exchanges bound can also be specified. -*/ -func (ch *Channel) ExchangeBind(destination, key, source string, noWait bool, args Table) error { - if err := args.Validate(); err != nil { - return err - } - - return ch.call( - &exchangeBind{ - Destination: destination, - Source: source, - RoutingKey: key, - NoWait: noWait, - Arguments: args, - }, - &exchangeBindOk{}, - ) -} - -/* -ExchangeUnbind unbinds the destination exchange from the source exchange on the -server by removing the routing key between them. This is the inverse of -ExchangeBind. If the binding does not currently exist, an error will be -returned. - -When noWait is true, do not wait for the server to confirm the deletion of the -binding. If any error occurs the channel will be closed. Add a listener to -NotifyClose to handle these errors. - -Optional arguments that are specific to the type of exchanges bound can also be -provided. These must match the same arguments specified in ExchangeBind to -identify the binding. -*/ -func (ch *Channel) ExchangeUnbind(destination, key, source string, noWait bool, args Table) error { - if err := args.Validate(); err != nil { - return err - } - - return ch.call( - &exchangeUnbind{ - Destination: destination, - Source: source, - RoutingKey: key, - NoWait: noWait, - Arguments: args, - }, - &exchangeUnbindOk{}, - ) -} - -/* -Publish sends a Publishing from the client to an exchange on the server. - -When you want a single message to be delivered to a single queue, you can -publish to the default exchange with the routingKey of the queue name. This is -because every declared queue gets an implicit route to the default exchange. - -Since publishings are asynchronous, any undeliverable message will get returned -by the server. Add a listener with Channel.NotifyReturn to handle any -undeliverable message when calling publish with either the mandatory or -immediate parameters as true. - -Publishings can be undeliverable when the mandatory flag is true and no queue is -bound that matches the routing key, or when the immediate flag is true and no -consumer on the matched queue is ready to accept the delivery. - -This can return an error when the channel, connection or socket is closed. The -error or lack of an error does not indicate whether the server has received this -publishing. - -It is possible for publishing to not reach the broker if the underlying socket -is shut down without pending publishing packets being flushed from the kernel -buffers. The easy way of making it probable that all publishings reach the -server is to always call Connection.Close before terminating your publishing -application. The way to ensure that all publishings reach the server is to add -a listener to Channel.NotifyPublish and put the channel in confirm mode with -Channel.Confirm. Publishing delivery tags and their corresponding -confirmations start at 1. Exit when all publishings are confirmed. - -When Publish does not return an error and the channel is in confirm mode, the -internal counter for DeliveryTags with the first confirmation starts at 1. - -Deprecated: Use PublishWithContext instead. -*/ -func (ch *Channel) Publish(exchange, key string, mandatory, immediate bool, msg Publishing) error { - _, err := ch.PublishWithDeferredConfirmWithContext(context.Background(), exchange, key, mandatory, immediate, msg) - return err -} - -/* -PublishWithContext sends a Publishing from the client to an exchange on the server. - -When you want a single message to be delivered to a single queue, you can -publish to the default exchange with the routingKey of the queue name. This is -because every declared queue gets an implicit route to the default exchange. - -Since publishings are asynchronous, any undeliverable message will get returned -by the server. Add a listener with Channel.NotifyReturn to handle any -undeliverable message when calling publish with either the mandatory or -immediate parameters as true. - -Publishings can be undeliverable when the mandatory flag is true and no queue is -bound that matches the routing key, or when the immediate flag is true and no -consumer on the matched queue is ready to accept the delivery. - -This can return an error when the channel, connection or socket is closed. The -error or lack of an error does not indicate whether the server has received this -publishing. - -It is possible for publishing to not reach the broker if the underlying socket -is shut down without pending publishing packets being flushed from the kernel -buffers. The easy way of making it probable that all publishings reach the -server is to always call Connection.Close before terminating your publishing -application. The way to ensure that all publishings reach the server is to add -a listener to Channel.NotifyPublish and put the channel in confirm mode with -Channel.Confirm. Publishing delivery tags and their corresponding -confirmations start at 1. Exit when all publishings are confirmed. - -When Publish does not return an error and the channel is in confirm mode, the -internal counter for DeliveryTags with the first confirmation starts at 1. -*/ -func (ch *Channel) PublishWithContext(ctx context.Context, exchange, key string, mandatory, immediate bool, msg Publishing) error { - _, err := ch.PublishWithDeferredConfirmWithContext(ctx, exchange, key, mandatory, immediate, msg) - return err -} - -/* -PublishWithDeferredConfirm behaves identically to Publish but additionally returns a -DeferredConfirmation, allowing the caller to wait on the publisher confirmation -for this message. If the channel has not been put into confirm mode, -the DeferredConfirmation will be nil. - -Deprecated: Use PublishWithDeferredConfirmWithContext instead. -*/ -func (ch *Channel) PublishWithDeferredConfirm(exchange, key string, mandatory, immediate bool, msg Publishing) (*DeferredConfirmation, error) { - return ch.PublishWithDeferredConfirmWithContext(context.Background(), exchange, key, mandatory, immediate, msg) -} - -/* -PublishWithDeferredConfirmWithContext behaves identically to Publish but additionally returns a -DeferredConfirmation, allowing the caller to wait on the publisher confirmation -for this message. If the channel has not been put into confirm mode, -the DeferredConfirmation will be nil. -*/ -func (ch *Channel) PublishWithDeferredConfirmWithContext(ctx context.Context, exchange, key string, mandatory, immediate bool, msg Publishing) (*DeferredConfirmation, error) { - if ctx == nil { - return nil, errors.New("amqp091-go: nil Context") - } - - if err := msg.Headers.Validate(); err != nil { - return nil, err - } - - ch.m.Lock() - defer ch.m.Unlock() - - var dc *DeferredConfirmation - if ch.confirming { - dc = ch.confirms.publish() - } - - if err := ch.send(&basicPublish{ - Exchange: exchange, - RoutingKey: key, - Mandatory: mandatory, - Immediate: immediate, - Body: msg.Body, - Properties: properties{ - Headers: msg.Headers, - ContentType: msg.ContentType, - ContentEncoding: msg.ContentEncoding, - DeliveryMode: msg.DeliveryMode, - Priority: msg.Priority, - CorrelationId: msg.CorrelationId, - ReplyTo: msg.ReplyTo, - Expiration: msg.Expiration, - MessageId: msg.MessageId, - Timestamp: msg.Timestamp, - Type: msg.Type, - UserId: msg.UserId, - AppId: msg.AppId, - }, - }); err != nil { - if ch.confirming { - ch.confirms.unpublish() - } - return nil, err - } - - return dc, nil -} - -/* -Get synchronously receives a single Delivery from the head of a queue from the -server to the client. In almost all cases, using Channel.Consume will be -preferred. - -If there was a delivery waiting on the queue and that delivery was received, the -second return value will be true. If there was no delivery waiting or an error -occurred, the ok bool will be false. - -All deliveries must be acknowledged including those from Channel.Get. Call -Delivery.Ack on the returned delivery when you have fully processed this -delivery. - -When autoAck is true, the server will automatically acknowledge this message so -you don't have to. But if you are unable to fully process this message before -the channel or connection is closed, the message will not get requeued. -*/ -func (ch *Channel) Get(queue string, autoAck bool) (msg Delivery, ok bool, err error) { - req := &basicGet{Queue: queue, NoAck: autoAck} - res := &basicGetOk{} - empty := &basicGetEmpty{} - - if err := ch.call(req, res, empty); err != nil { - return Delivery{}, false, err - } - - if res.DeliveryTag > 0 { - return *(newDelivery(ch, res)), true, nil - } - - return Delivery{}, false, nil -} - -/* -Tx puts the channel into transaction mode on the server. All publishings and -acknowledgments following this method will be atomically committed or rolled -back for a single queue. Call either Channel.TxCommit or Channel.TxRollback to -leave a this transaction and immediately start a new transaction. - -The atomicity across multiple queues is not defined as queue declarations and -bindings are not included in the transaction. - -The behavior of publishings that are delivered as mandatory or immediate while -the channel is in a transaction is not defined. - -Once a channel has been put into transaction mode, it cannot be taken out of -transaction mode. Use a different channel for non-transactional semantics. -*/ -func (ch *Channel) Tx() error { - return ch.call( - &txSelect{}, - &txSelectOk{}, - ) -} - -/* -TxCommit atomically commits all publishings and acknowledgments for a single -queue and immediately start a new transaction. - -Calling this method without having called Channel.Tx is an error. -*/ -func (ch *Channel) TxCommit() error { - return ch.call( - &txCommit{}, - &txCommitOk{}, - ) -} - -/* -TxRollback atomically rolls back all publishings and acknowledgments for a -single queue and immediately start a new transaction. - -Calling this method without having called Channel.Tx is an error. -*/ -func (ch *Channel) TxRollback() error { - return ch.call( - &txRollback{}, - &txRollbackOk{}, - ) -} - -/* -Flow pauses the delivery of messages to consumers on this channel. Channels -are opened with flow control active, to open a channel with paused -deliveries immediately call this method with `false` after calling -Connection.Channel. - -When active is `false`, this method asks the server to temporarily pause deliveries -until called again with active as `true`. - -Channel.Get methods will not be affected by flow control. - -This method is not intended to act as window control. Use Channel.Qos to limit -the number of unacknowledged messages or bytes in flight instead. - -The server may also send us flow methods to throttle our publishings. A well -behaving publishing client should add a listener with Channel.NotifyFlow and -pause its publishings when `false` is sent on that channel. - -Note: RabbitMQ prefers to use TCP push back to control flow for all channels on -a connection, so under high volume scenarios, it's wise to open separate -Connections for publishings and deliveries. -*/ -func (ch *Channel) Flow(active bool) error { - return ch.call( - &channelFlow{Active: active}, - &channelFlowOk{}, - ) -} - -/* -Confirm puts this channel into confirm mode so that the client can ensure all -publishings have successfully been received by the server. After entering this -mode, the server will send a basic.ack or basic.nack message with the deliver -tag set to a 1 based incremental index corresponding to every publishing -received after the this method returns. - -Add a listener to Channel.NotifyPublish to respond to the Confirmations. If -Channel.NotifyPublish is not called, the Confirmations will be silently -ignored. - -The order of acknowledgments is not bound to the order of deliveries. - -Ack and Nack confirmations will arrive at some point in the future. - -Unroutable mandatory or immediate messages are acknowledged immediately after -any Channel.NotifyReturn listeners have been notified. Other messages are -acknowledged when all queues that should have the message routed to them have -either received acknowledgment of delivery or have enqueued the message, -persisting the message if necessary. - -When noWait is true, the client will not wait for a response. A channel -exception could occur if the server does not support this method. -*/ -func (ch *Channel) Confirm(noWait bool) error { - if err := ch.call( - &confirmSelect{Nowait: noWait}, - &confirmSelectOk{}, - ); err != nil { - return err - } - - ch.confirmM.Lock() - ch.confirming = true - ch.confirmM.Unlock() - - return nil -} - -/* -Recover redelivers all unacknowledged deliveries on this channel. - -When requeue is false, messages will be redelivered to the original consumer. - -When requeue is true, messages will be redelivered to any available consumer, -potentially including the original. - -If the deliveries cannot be recovered, an error will be returned and the channel -will be closed. - -Note: this method is not implemented on RabbitMQ, use Delivery.Nack instead - -Deprecated: This method is deprecated in RabbitMQ. RabbitMQ used Recover(true) -as a mechanism for consumers to tell the broker that they were ready for more -deliveries, back in 2008-2009. Support for this will be removed from RabbitMQ in -a future release. Use Nack() with requeue=true instead. -*/ -func (ch *Channel) Recover(requeue bool) error { - return ch.call( - &basicRecover{Requeue: requeue}, - &basicRecoverOk{}, - ) -} - -/* -Ack acknowledges a delivery by its delivery tag when having been consumed with -Channel.Consume or Channel.Get. - -Ack acknowledges all message received prior to the delivery tag when multiple -is true. - -See also Delivery.Ack -*/ -func (ch *Channel) Ack(tag uint64, multiple bool) error { - ch.m.Lock() - defer ch.m.Unlock() - - return ch.send(&basicAck{ - DeliveryTag: tag, - Multiple: multiple, - }) -} - -/* -Nack negatively acknowledges a delivery by its delivery tag. Prefer this -method to notify the server that you were not able to process this delivery and -it must be redelivered or dropped. - -See also Delivery.Nack -*/ -func (ch *Channel) Nack(tag uint64, multiple bool, requeue bool) error { - ch.m.Lock() - defer ch.m.Unlock() - - return ch.send(&basicNack{ - DeliveryTag: tag, - Multiple: multiple, - Requeue: requeue, - }) -} - -/* -Reject negatively acknowledges a delivery by its delivery tag. Prefer Nack -over Reject when communicating with a RabbitMQ server because you can Nack -multiple messages, reducing the amount of protocol messages to exchange. - -See also Delivery.Reject -*/ -func (ch *Channel) Reject(tag uint64, requeue bool) error { - ch.m.Lock() - defer ch.m.Unlock() - - return ch.send(&basicReject{ - DeliveryTag: tag, - Requeue: requeue, - }) -} - -// GetNextPublishSeqNo returns the sequence number of the next message to be -// published, when in confirm mode. -func (ch *Channel) GetNextPublishSeqNo() uint64 { - ch.confirms.m.Lock() - defer ch.confirms.m.Unlock() - - return ch.confirms.published + 1 -} diff --git a/vendor/github.com/rabbitmq/amqp091-go/confirms.go b/vendor/github.com/rabbitmq/amqp091-go/confirms.go deleted file mode 100644 index 577e042..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/confirms.go +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. -// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package amqp091 - -import ( - "context" - "sync" -) - -// confirms resequences and notifies one or multiple publisher confirmation listeners -type confirms struct { - m sync.Mutex - listeners []chan Confirmation - sequencer map[uint64]Confirmation - deferredConfirmations *deferredConfirmations - published uint64 - publishedMut sync.Mutex - expecting uint64 -} - -// newConfirms allocates a confirms -func newConfirms() *confirms { - return &confirms{ - sequencer: map[uint64]Confirmation{}, - deferredConfirmations: newDeferredConfirmations(), - published: 0, - expecting: 1, - } -} - -func (c *confirms) Listen(l chan Confirmation) { - c.m.Lock() - defer c.m.Unlock() - - c.listeners = append(c.listeners, l) -} - -// Publish increments the publishing counter -func (c *confirms) publish() *DeferredConfirmation { - c.publishedMut.Lock() - defer c.publishedMut.Unlock() - - c.published++ - return c.deferredConfirmations.Add(c.published) -} - -// unpublish decrements the publishing counter and removes the -// DeferredConfirmation. It must be called immediately after a publish fails. -func (c *confirms) unpublish() { - c.publishedMut.Lock() - defer c.publishedMut.Unlock() - c.deferredConfirmations.remove(c.published) - c.published-- -} - -// confirm confirms one publishing, increments the expecting delivery tag, and -// removes bookkeeping for that delivery tag. -func (c *confirms) confirm(confirmation Confirmation) { - delete(c.sequencer, c.expecting) - c.expecting++ - for _, l := range c.listeners { - l <- confirmation - } -} - -// resequence confirms any out of order delivered confirmations -func (c *confirms) resequence() { - c.publishedMut.Lock() - defer c.publishedMut.Unlock() - - for c.expecting <= c.published { - sequenced, found := c.sequencer[c.expecting] - if !found { - return - } - c.confirm(sequenced) - } -} - -// One confirms one publishing and all following in the publishing sequence -func (c *confirms) One(confirmed Confirmation) { - c.m.Lock() - defer c.m.Unlock() - - c.deferredConfirmations.Confirm(confirmed) - - if c.expecting == confirmed.DeliveryTag { - c.confirm(confirmed) - } else { - c.sequencer[confirmed.DeliveryTag] = confirmed - } - c.resequence() -} - -// Multiple confirms all publishings up until the delivery tag -func (c *confirms) Multiple(confirmed Confirmation) { - c.m.Lock() - defer c.m.Unlock() - - c.deferredConfirmations.ConfirmMultiple(confirmed) - - for c.expecting <= confirmed.DeliveryTag { - c.confirm(Confirmation{c.expecting, confirmed.Ack}) - } - c.resequence() -} - -// Cleans up the confirms struct and its dependencies. -// Closes all listeners, discarding any out of sequence confirmations -func (c *confirms) Close() error { - c.m.Lock() - defer c.m.Unlock() - - c.deferredConfirmations.Close() - - for _, l := range c.listeners { - close(l) - } - c.listeners = nil - return nil -} - -type deferredConfirmations struct { - m sync.Mutex - confirmations map[uint64]*DeferredConfirmation -} - -func newDeferredConfirmations() *deferredConfirmations { - return &deferredConfirmations{ - confirmations: map[uint64]*DeferredConfirmation{}, - } -} - -func (d *deferredConfirmations) Add(tag uint64) *DeferredConfirmation { - d.m.Lock() - defer d.m.Unlock() - - dc := &DeferredConfirmation{DeliveryTag: tag} - dc.done = make(chan struct{}) - d.confirmations[tag] = dc - return dc -} - -// remove is only used to drop a tag whose publish failed -func (d *deferredConfirmations) remove(tag uint64) { - d.m.Lock() - defer d.m.Unlock() - dc, found := d.confirmations[tag] - if !found { - return - } - close(dc.done) - delete(d.confirmations, tag) -} - -func (d *deferredConfirmations) Confirm(confirmation Confirmation) { - d.m.Lock() - defer d.m.Unlock() - - dc, found := d.confirmations[confirmation.DeliveryTag] - if !found { - // We should never receive a confirmation for a tag that hasn't - // been published, but a test causes this to happen. - return - } - dc.setAck(confirmation.Ack) - delete(d.confirmations, confirmation.DeliveryTag) -} - -func (d *deferredConfirmations) ConfirmMultiple(confirmation Confirmation) { - d.m.Lock() - defer d.m.Unlock() - - for k, v := range d.confirmations { - if k <= confirmation.DeliveryTag { - v.setAck(confirmation.Ack) - delete(d.confirmations, k) - } - } -} - -// Close nacks all pending DeferredConfirmations being blocked by dc.Wait(). -func (d *deferredConfirmations) Close() { - d.m.Lock() - defer d.m.Unlock() - - for k, v := range d.confirmations { - v.setAck(false) - delete(d.confirmations, k) - } -} - -// setAck sets the acknowledgement status of the confirmation. Note that it must -// not be called more than once. -func (d *DeferredConfirmation) setAck(ack bool) { - d.ack = ack - close(d.done) -} - -// Done returns the channel that can be used to wait for the publisher -// confirmation. -func (d *DeferredConfirmation) Done() <-chan struct{} { - return d.done -} - -// Acked returns the publisher confirmation in a non-blocking manner. It returns -// false if the confirmation was not acknowledged yet or received negative -// acknowledgement. -func (d *DeferredConfirmation) Acked() bool { - select { - case <-d.done: - default: - return false - } - return d.ack -} - -// Wait blocks until the publisher confirmation. It returns true if the server -// successfully received the publishing. -func (d *DeferredConfirmation) Wait() bool { - <-d.done - return d.ack -} - -// WaitContext waits until the publisher confirmation. It returns true if the -// server successfully received the publishing. If the context expires before -// that, ctx.Err() is returned. -func (d *DeferredConfirmation) WaitContext(ctx context.Context) (bool, error) { - select { - case <-ctx.Done(): - return false, ctx.Err() - case <-d.done: - } - return d.ack, nil -} diff --git a/vendor/github.com/rabbitmq/amqp091-go/connection.go b/vendor/github.com/rabbitmq/amqp091-go/connection.go deleted file mode 100644 index abe4b02..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/connection.go +++ /dev/null @@ -1,1099 +0,0 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. -// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package amqp091 - -import ( - "bufio" - "crypto/tls" - "crypto/x509" - "errors" - "fmt" - "io" - "net" - "os" - "reflect" - "strconv" - "strings" - "sync" - "sync/atomic" - "time" -) - -const ( - maxChannelMax = (2 << 15) - 1 - - defaultHeartbeat = 10 * time.Second - defaultConnectionTimeout = 30 * time.Second - defaultProduct = "AMQP 0.9.1 Client" - buildVersion = "1.6.0" - platform = "golang" - // Safer default that makes channel leaks a lot easier to spot - // before they create operational headaches. See https://github.com/rabbitmq/rabbitmq-server/issues/1593. - defaultChannelMax = (2 << 10) - 1 - defaultLocale = "en_US" -) - -// Config is used in DialConfig and Open to specify the desired tuning -// parameters used during a connection open handshake. The negotiated tuning -// will be stored in the returned connection's Config field. -type Config struct { - // The SASL mechanisms to try in the client request, and the successful - // mechanism used on the Connection object. - // If SASL is nil, PlainAuth from the URL is used. - SASL []Authentication - - // Vhost specifies the namespace of permissions, exchanges, queues and - // bindings on the server. Dial sets this to the path parsed from the URL. - Vhost string - - ChannelMax int // 0 max channels means 2^16 - 1 - FrameSize int // 0 max bytes means unlimited - Heartbeat time.Duration // less than 1s uses the server's interval - - // TLSClientConfig specifies the client configuration of the TLS connection - // when establishing a tls transport. - // If the URL uses an amqps scheme, then an empty tls.Config with the - // ServerName from the URL is used. - TLSClientConfig *tls.Config - - // Properties is table of properties that the client advertises to the server. - // This is an optional setting - if the application does not set this, - // the underlying library will use a generic set of client properties. - Properties Table - - // Connection locale that we expect to always be en_US - // Even though servers must return it as per the AMQP 0-9-1 spec, - // we are not aware of it being used other than to satisfy the spec requirements - Locale string - - // Dial returns a net.Conn prepared for a TLS handshake with TSLClientConfig, - // then an AMQP connection handshake. - // If Dial is nil, net.DialTimeout with a 30s connection and 30s deadline is - // used during TLS and AMQP handshaking. - Dial func(network, addr string) (net.Conn, error) -} - -// NewConnectionProperties creates an amqp.Table to be used as amqp.Config.Properties. -// -// Defaults to library-defined values. For empty properties, use make(amqp.Table) instead. -func NewConnectionProperties() Table { - return Table{ - "product": defaultProduct, - "version": buildVersion, - "platform": platform, - } -} - -// Connection manages the serialization and deserialization of frames from IO -// and dispatches the frames to the appropriate channel. All RPC methods and -// asynchronous Publishing, Delivery, Ack, Nack and Return messages are -// multiplexed on this channel. There must always be active receivers for -// every asynchronous message on this connection. -type Connection struct { - destructor sync.Once // shutdown once - sendM sync.Mutex // conn writer mutex - m sync.Mutex // struct field mutex - - conn io.ReadWriteCloser - - rpc chan message - writer *writer - sends chan time.Time // timestamps of each frame sent - deadlines chan readDeadliner // heartbeater updates read deadlines - - allocator *allocator // id generator valid after openTune - channels map[uint16]*Channel - - noNotify bool // true when we will never notify again - closes []chan *Error - blocks []chan Blocking - - errors chan *Error - - Config Config // The negotiated Config after connection.open - - Major int // Server's major version - Minor int // Server's minor version - Properties Table // Server properties - Locales []string // Server locales - - closed int32 // Will be 1 if the connection is closed, 0 otherwise. Should only be accessed as atomic -} - -type readDeadliner interface { - SetReadDeadline(time.Time) error -} - -// DefaultDial establishes a connection when config.Dial is not provided -func DefaultDial(connectionTimeout time.Duration) func(network, addr string) (net.Conn, error) { - return func(network, addr string) (net.Conn, error) { - conn, err := net.DialTimeout(network, addr, connectionTimeout) - if err != nil { - return nil, err - } - - // Heartbeating hasn't started yet, don't stall forever on a dead server. - // A deadline is set for TLS and AMQP handshaking. After AMQP is established, - // the deadline is cleared in openComplete. - if err := conn.SetDeadline(time.Now().Add(connectionTimeout)); err != nil { - return nil, err - } - - return conn, nil - } -} - -// Dial accepts a string in the AMQP URI format and returns a new Connection -// over TCP using PlainAuth. Defaults to a server heartbeat interval of 10 -// seconds and sets the handshake deadline to 30 seconds. After handshake, -// deadlines are cleared. -// -// Dial uses the zero value of tls.Config when it encounters an amqps:// -// scheme. It is equivalent to calling DialTLS(amqp, nil). -func Dial(url string) (*Connection, error) { - return DialConfig(url, Config{ - Heartbeat: defaultHeartbeat, - Locale: defaultLocale, - }) -} - -// DialTLS accepts a string in the AMQP URI format and returns a new Connection -// over TCP using PlainAuth. Defaults to a server heartbeat interval of 10 -// seconds and sets the initial read deadline to 30 seconds. -// -// DialTLS uses the provided tls.Config when encountering an amqps:// scheme. -func DialTLS(url string, amqps *tls.Config) (*Connection, error) { - return DialConfig(url, Config{ - Heartbeat: defaultHeartbeat, - TLSClientConfig: amqps, - Locale: defaultLocale, - }) -} - -// DialTLS_ExternalAuth accepts a string in the AMQP URI format and returns a -// new Connection over TCP using EXTERNAL auth. Defaults to a server heartbeat -// interval of 10 seconds and sets the initial read deadline to 30 seconds. -// -// This mechanism is used, when RabbitMQ is configured for EXTERNAL auth with -// ssl_cert_login plugin for userless/passwordless logons -// -// DialTLS_ExternalAuth uses the provided tls.Config when encountering an -// amqps:// scheme. -func DialTLS_ExternalAuth(url string, amqps *tls.Config) (*Connection, error) { - return DialConfig(url, Config{ - Heartbeat: defaultHeartbeat, - TLSClientConfig: amqps, - SASL: []Authentication{&ExternalAuth{}}, - }) -} - -// DialConfig accepts a string in the AMQP URI format and a configuration for -// the transport and connection setup, returning a new Connection. Defaults to -// a server heartbeat interval of 10 seconds and sets the initial read deadline -// to 30 seconds. -func DialConfig(url string, config Config) (*Connection, error) { - var err error - var conn net.Conn - - uri, err := ParseURI(url) - if err != nil { - return nil, err - } - - if config.SASL == nil { - config.SASL = []Authentication{uri.PlainAuth()} - } - - if config.Vhost == "" { - config.Vhost = uri.Vhost - } - - addr := net.JoinHostPort(uri.Host, strconv.FormatInt(int64(uri.Port), 10)) - - dialer := config.Dial - if dialer == nil { - dialer = DefaultDial(defaultConnectionTimeout) - } - - conn, err = dialer("tcp", addr) - if err != nil { - return nil, err - } - - if uri.Scheme == "amqps" { - if config.TLSClientConfig == nil { - tlsConfig, err := tlsConfigFromURI(uri) - if err != nil { - return nil, fmt.Errorf("create TLS config from URI: %w", err) - } - config.TLSClientConfig = tlsConfig - } - - // If ServerName has not been specified in TLSClientConfig, - // set it to the URI host used for this connection. - if config.TLSClientConfig.ServerName == "" { - config.TLSClientConfig.ServerName = uri.Host - } - - client := tls.Client(conn, config.TLSClientConfig) - if err := client.Handshake(); err != nil { - conn.Close() - return nil, err - } - - conn = client - } - - return Open(conn, config) -} - -/* -Open accepts an already established connection, or other io.ReadWriteCloser as -a transport. Use this method if you have established a TLS connection or wish -to use your own custom transport. -*/ -func Open(conn io.ReadWriteCloser, config Config) (*Connection, error) { - c := &Connection{ - conn: conn, - writer: &writer{bufio.NewWriter(conn)}, - channels: make(map[uint16]*Channel), - rpc: make(chan message), - sends: make(chan time.Time), - errors: make(chan *Error, 1), - deadlines: make(chan readDeadliner, 1), - } - go c.reader(conn) - return c, c.open(config) -} - -/* -UpdateSecret updates the secret used to authenticate this connection. It is used when -secrets have an expiration date and need to be renewed, like OAuth 2 tokens. - -It returns an error if the operation is not successful, or if the connection is closed. -*/ -func (c *Connection) UpdateSecret(newSecret, reason string) error { - if c.IsClosed() { - return ErrClosed - } - return c.call(&connectionUpdateSecret{ - NewSecret: newSecret, - Reason: reason, - }, &connectionUpdateSecretOk{}) -} - -/* -LocalAddr returns the local TCP peer address, or ":0" (the zero value of net.TCPAddr) -as a fallback default value if the underlying transport does not support LocalAddr(). -*/ -func (c *Connection) LocalAddr() net.Addr { - if conn, ok := c.conn.(interface { - LocalAddr() net.Addr - }); ok { - return conn.LocalAddr() - } - return &net.TCPAddr{} -} - -/* -RemoteAddr returns the remote TCP peer address, if known. -*/ -func (c *Connection) RemoteAddr() net.Addr { - if conn, ok := c.conn.(interface { - RemoteAddr() net.Addr - }); ok { - return conn.RemoteAddr() - } - return &net.TCPAddr{} -} - -// ConnectionState returns basic TLS details of the underlying transport. -// Returns a zero value when the underlying connection does not implement -// ConnectionState() tls.ConnectionState. -func (c *Connection) ConnectionState() tls.ConnectionState { - if conn, ok := c.conn.(interface { - ConnectionState() tls.ConnectionState - }); ok { - return conn.ConnectionState() - } - return tls.ConnectionState{} -} - -/* -NotifyClose registers a listener for close events either initiated by an error -accompanying a connection.close method or by a normal shutdown. - -The chan provided will be closed when the Connection is closed and on a -graceful close, no error will be sent. - -In case of a non graceful close the error will be notified synchronously by the library -so that it will be necessary to consume the Channel from the caller in order to avoid deadlocks - -To reconnect after a transport or protocol error, register a listener here and -re-run your setup process. -*/ -func (c *Connection) NotifyClose(receiver chan *Error) chan *Error { - c.m.Lock() - defer c.m.Unlock() - - if c.noNotify { - close(receiver) - } else { - c.closes = append(c.closes, receiver) - } - - return receiver -} - -/* -NotifyBlocked registers a listener for RabbitMQ specific TCP flow control -method extensions connection.blocked and connection.unblocked. Flow control is -active with a reason when Blocking.Blocked is true. When a Connection is -blocked, all methods will block across all connections until server resources -become free again. - -This optional extension is supported by the server when the -"connection.blocked" server capability key is true. -*/ -func (c *Connection) NotifyBlocked(receiver chan Blocking) chan Blocking { - c.m.Lock() - defer c.m.Unlock() - - if c.noNotify { - close(receiver) - } else { - c.blocks = append(c.blocks, receiver) - } - - return receiver -} - -/* -Close requests and waits for the response to close the AMQP connection. - -It's advisable to use this message when publishing to ensure all kernel buffers -have been flushed on the server and client before exiting. - -An error indicates that server may not have received this request to close but -the connection should be treated as closed regardless. - -After returning from this call, all resources associated with this connection, -including the underlying io, Channels, Notify listeners and Channel consumers -will also be closed. -*/ -func (c *Connection) Close() error { - if c.IsClosed() { - return ErrClosed - } - - defer c.shutdown(nil) - return c.call( - &connectionClose{ - ReplyCode: replySuccess, - ReplyText: "kthxbai", - }, - &connectionCloseOk{}, - ) -} - -// CloseDeadline requests and waits for the response to close this AMQP connection. -// -// Accepts a deadline for waiting the server response. The deadline is passed -// to the low-level connection i.e. network socket. -// -// Regardless of the error returned, the connection is considered closed, and it -// should not be used after calling this function. -// -// In the event of an I/O timeout, connection-closed listeners are NOT informed. -// -// After returning from this call, all resources associated with this connection, -// including the underlying io, Channels, Notify listeners and Channel consumers -// will also be closed. -func (c *Connection) CloseDeadline(deadline time.Time) error { - if c.IsClosed() { - return ErrClosed - } - - defer c.shutdown(nil) - - err := c.setDeadline(deadline) - if err != nil { - return err - } - - return c.call( - &connectionClose{ - ReplyCode: replySuccess, - ReplyText: "kthxbai", - }, - &connectionCloseOk{}, - ) -} - -func (c *Connection) closeWith(err *Error) error { - if c.IsClosed() { - return ErrClosed - } - - defer c.shutdown(err) - - return c.call( - &connectionClose{ - ReplyCode: uint16(err.Code), - ReplyText: err.Reason, - }, - &connectionCloseOk{}, - ) -} - -// IsClosed returns true if the connection is marked as closed, otherwise false -// is returned. -func (c *Connection) IsClosed() bool { - return atomic.LoadInt32(&c.closed) == 1 -} - -// setDeadline is a wrapper to type assert Connection.conn and set an I/O -// deadline in the underlying TCP connection socket, by calling -// net.Conn.SetDeadline(). It returns an error, in case the type assertion fails, -// although this should never happen. -func (c *Connection) setDeadline(t time.Time) error { - con, ok := c.conn.(net.Conn) - if !ok { - return errInvalidTypeAssertion - } - return con.SetDeadline(t) -} - -func (c *Connection) send(f frame) error { - if c.IsClosed() { - return ErrClosed - } - - c.sendM.Lock() - err := c.writer.WriteFrame(f) - c.sendM.Unlock() - - if err != nil { - // shutdown could be re-entrant from signaling notify chans - go c.shutdown(&Error{ - Code: FrameError, - Reason: err.Error(), - }) - } else { - // Broadcast we sent a frame, reducing heartbeats, only - // if there is something that can receive - like a non-reentrant - // call or if the heartbeater isn't running - select { - case c.sends <- time.Now(): - default: - } - } - - return err -} - -// This method is intended to be used with sendUnflushed() to end a sequence -// of sendUnflushed() calls and flush the connection -func (c *Connection) endSendUnflushed() error { - c.sendM.Lock() - defer c.sendM.Unlock() - return c.flush() -} - -// sendUnflushed performs an *Unflushed* write. It is otherwise equivalent to -// send(), and we provide a separate flush() function to explicitly flush the -// buffer after all Frames are written. -// -// Why is this a thing? -// -// send() method uses writer.WriteFrame(), which will write the Frame then -// flush the buffer. For cases like the sendOpen() method on Channel, which -// sends multiple Frames (methodFrame, headerFrame, N x bodyFrame), flushing -// after each Frame is inefficient as it negates much of the benefit of using a -// buffered writer, and results in more syscalls than necessary. Flushing buffers -// after every frame can have a significant performance impact when sending -// (basicPublish) small messages, so this method performs an *Unflushed* write -// but is otherwise equivalent to send() method, and we provide a separate -// flush method to explicitly flush the buffer after all Frames are written. -func (c *Connection) sendUnflushed(f frame) error { - if c.IsClosed() { - return ErrClosed - } - - c.sendM.Lock() - err := c.writer.WriteFrameNoFlush(f) - c.sendM.Unlock() - - if err != nil { - // shutdown could be re-entrant from signaling notify chans - go c.shutdown(&Error{ - Code: FrameError, - Reason: err.Error(), - }) - } - - return err -} - -// This method is intended to be used with sendUnflushed() to explicitly flush -// the buffer after all required Frames have been written to the buffer. -func (c *Connection) flush() (err error) { - if buf, ok := c.writer.w.(*bufio.Writer); ok { - err = buf.Flush() - - // Moving send notifier to flush increases basicPublish for the small message - // case. As sendUnflushed + flush is used for the case of sending semantically - // related Frames (e.g. a Message like basicPublish) there is no real advantage - // to sending per Frame vice per "group of related Frames" and for the case of - // small messages time.Now() is (relatively) expensive. - if err == nil { - // Broadcast we sent a frame, reducing heartbeats, only - // if there is something that can receive - like a non-reentrant - // call or if the heartbeater isn't running - select { - case c.sends <- time.Now(): - default: - } - } - } - - return -} - -func (c *Connection) shutdown(err *Error) { - atomic.StoreInt32(&c.closed, 1) - - c.destructor.Do(func() { - c.m.Lock() - defer c.m.Unlock() - - if err != nil { - for _, c := range c.closes { - c <- err - } - c.errors <- err - } - // Shutdown handler goroutine can still receive the result. - close(c.errors) - - for _, c := range c.closes { - close(c) - } - - for _, c := range c.blocks { - close(c) - } - - // Shutdown the channel, but do not use closeChannel() as it calls - // releaseChannel() which requires the connection lock. - // - // Ranging over c.channels and calling releaseChannel() that mutates - // c.channels is racy - see commit 6063341 for an example. - for _, ch := range c.channels { - ch.shutdown(err) - } - - c.conn.Close() - - c.channels = nil - c.allocator = nil - c.noNotify = true - }) -} - -// All methods sent to the connection channel should be synchronous so we -// can handle them directly without a framing component -func (c *Connection) demux(f frame) { - if f.channel() == 0 { - c.dispatch0(f) - } else { - c.dispatchN(f) - } -} - -func (c *Connection) dispatch0(f frame) { - switch mf := f.(type) { - case *methodFrame: - switch m := mf.Method.(type) { - case *connectionClose: - // Send immediately as shutdown will close our side of the writer. - f := &methodFrame{ChannelId: 0, Method: &connectionCloseOk{}} - if err := c.send(f); err != nil { - Logger.Printf("error sending connectionCloseOk, error: %+v", err) - } - c.shutdown(newError(m.ReplyCode, m.ReplyText)) - case *connectionBlocked: - for _, c := range c.blocks { - c <- Blocking{Active: true, Reason: m.Reason} - } - case *connectionUnblocked: - for _, c := range c.blocks { - c <- Blocking{Active: false} - } - default: - c.rpc <- m - } - case *heartbeatFrame: - // kthx - all reads reset our deadline. so we can drop this - default: - // lolwat - channel0 only responds to methods and heartbeats - if err := c.closeWith(ErrUnexpectedFrame); err != nil { - Logger.Printf("error sending connectionCloseOk with ErrUnexpectedFrame, error: %+v", err) - } - } -} - -func (c *Connection) dispatchN(f frame) { - c.m.Lock() - channel, ok := c.channels[f.channel()] - if ok { - updateChannel(f, channel) - } else { - Logger.Printf("[debug] dropping frame, channel %d does not exist", f.channel()) - } - c.m.Unlock() - - // Note: this could result in concurrent dispatch depending on - // how channels are managed in an application - if ok { - channel.recv(channel, f) - } else { - c.dispatchClosed(f) - } -} - -// section 2.3.7: "When a peer decides to close a channel or connection, it -// sends a Close method. The receiving peer MUST respond to a Close with a -// Close-Ok, and then both parties can close their channel or connection. Note -// that if peers ignore Close, deadlock can happen when both peers send Close -// at the same time." -// -// When we don't have a channel, so we must respond with close-ok on a close -// method. This can happen between a channel exception on an asynchronous -// method like basic.publish and a synchronous close with channel.close. -// In that case, we'll get both a channel.close and channel.close-ok in any -// order. -func (c *Connection) dispatchClosed(f frame) { - // Only consider method frames, drop content/header frames - if mf, ok := f.(*methodFrame); ok { - switch mf.Method.(type) { - case *channelClose: - f := &methodFrame{ChannelId: f.channel(), Method: &channelCloseOk{}} - if err := c.send(f); err != nil { - Logger.Printf("error sending channelCloseOk, channel id: %d error: %+v", f.channel(), err) - } - case *channelCloseOk: - // we are already closed, so do nothing - default: - // unexpected method on closed channel - if err := c.closeWith(ErrClosed); err != nil { - Logger.Printf("error sending connectionCloseOk with ErrClosed, error: %+v", err) - } - } - } -} - -// Reads each frame off the IO and hand off to the connection object that -// will demux the streams and dispatch to one of the opened channels or -// handle on channel 0 (the connection channel). -func (c *Connection) reader(r io.Reader) { - buf := bufio.NewReader(r) - frames := &reader{buf} - conn, haveDeadliner := r.(readDeadliner) - - defer close(c.rpc) - - for { - frame, err := frames.ReadFrame() - - if err != nil { - c.shutdown(&Error{Code: FrameError, Reason: err.Error()}) - return - } - - c.demux(frame) - - if haveDeadliner { - select { - case c.deadlines <- conn: - default: - // On c.Close() c.heartbeater() might exit just before c.deadlines <- conn is called. - // Which results in this goroutine being stuck forever. - } - } - } -} - -// Ensures that at least one frame is being sent at the tuned interval with a -// jitter tolerance of 1s -func (c *Connection) heartbeater(interval time.Duration, done chan *Error) { - const maxServerHeartbeatsInFlight = 3 - - var sendTicks <-chan time.Time - if interval > 0 { - ticker := time.NewTicker(interval) - defer ticker.Stop() - sendTicks = ticker.C - } - - lastSent := time.Now() - - for { - select { - case at, stillSending := <-c.sends: - // When actively sending, depend on sent frames to reset server timer - if stillSending { - lastSent = at - } else { - return - } - - case at := <-sendTicks: - // When idle, fill the space with a heartbeat frame - if at.Sub(lastSent) > interval-time.Second { - if err := c.send(&heartbeatFrame{}); err != nil { - // send heartbeats even after close/closeOk so we - // tick until the connection starts erroring - return - } - } - - case conn := <-c.deadlines: - // When reading, reset our side of the deadline, if we've negotiated one with - // a deadline that covers at least 2 server heartbeats - if interval > 0 { - if err := conn.SetReadDeadline(time.Now().Add(maxServerHeartbeatsInFlight * interval)); err != nil { - var opErr *net.OpError - if !errors.As(err, &opErr) { - Logger.Printf("error setting read deadline in heartbeater: %+v", err) - return - } - } - } - - case <-done: - return - } - } -} - -// Convenience method to inspect the Connection.Properties["capabilities"] -// Table for server identified capabilities like "basic.ack" or -// "confirm.select". -func (c *Connection) isCapable(featureName string) bool { - capabilities, _ := c.Properties["capabilities"].(Table) - hasFeature, _ := capabilities[featureName].(bool) - return hasFeature -} - -// allocateChannel records but does not open a new channel with a unique id. -// This method is the initial part of the channel lifecycle and paired with -// releaseChannel -func (c *Connection) allocateChannel() (*Channel, error) { - c.m.Lock() - defer c.m.Unlock() - - if c.IsClosed() { - return nil, ErrClosed - } - - id, ok := c.allocator.next() - if !ok { - return nil, ErrChannelMax - } - - ch := newChannel(c, uint16(id)) - c.channels[uint16(id)] = ch - - return ch, nil -} - -// releaseChannel removes a channel from the registry as the final part of the -// channel lifecycle -func (c *Connection) releaseChannel(id uint16) { - c.m.Lock() - defer c.m.Unlock() - - if !c.IsClosed() { - delete(c.channels, id) - c.allocator.release(int(id)) - } -} - -// openChannel allocates and opens a channel, must be paired with closeChannel -func (c *Connection) openChannel() (*Channel, error) { - ch, err := c.allocateChannel() - if err != nil { - return nil, err - } - - if err := ch.open(); err != nil { - c.releaseChannel(ch.id) - return nil, err - } - return ch, nil -} - -// closeChannel releases and initiates a shutdown of the channel. All channel -// closures should be initiated here for proper channel lifecycle management on -// this connection. -func (c *Connection) closeChannel(ch *Channel, e *Error) { - ch.shutdown(e) - c.releaseChannel(ch.id) -} - -/* -Channel opens a unique, concurrent server channel to process the bulk of AMQP -messages. Any error from methods on this receiver will render the receiver -invalid and a new Channel should be opened. -*/ -func (c *Connection) Channel() (*Channel, error) { - return c.openChannel() -} - -func (c *Connection) call(req message, res ...message) error { - // Special case for when the protocol header frame is sent insted of a - // request method - if req != nil { - if err := c.send(&methodFrame{ChannelId: 0, Method: req}); err != nil { - return err - } - } - - msg, ok := <-c.rpc - if !ok { - err, errorsChanIsOpen := <-c.errors - if !errorsChanIsOpen { - return ErrClosed - } - return err - } - - // Try to match one of the result types - for _, try := range res { - if reflect.TypeOf(msg) == reflect.TypeOf(try) { - // *res = *msg - vres := reflect.ValueOf(try).Elem() - vmsg := reflect.ValueOf(msg).Elem() - vres.Set(vmsg) - return nil - } - } - return ErrCommandInvalid -} - -// Communication flow to open, use and close a connection. 'C:' are -// frames sent by the Client. 'S:' are frames sent by the Server. -// -// Connection = open-Connection *use-Connection close-Connection -// -// open-Connection = C:protocol-header -// S:START C:START-OK -// *challenge -// S:TUNE C:TUNE-OK -// C:OPEN S:OPEN-OK -// -// challenge = S:SECURE C:SECURE-OK -// -// use-Connection = *channel -// -// close-Connection = C:CLOSE S:CLOSE-OK -// S:CLOSE C:CLOSE-OK -func (c *Connection) open(config Config) error { - if err := c.send(&protocolHeader{}); err != nil { - return err - } - - return c.openStart(config) -} - -func (c *Connection) openStart(config Config) error { - start := &connectionStart{} - - if err := c.call(nil, start); err != nil { - return err - } - - c.Major = int(start.VersionMajor) - c.Minor = int(start.VersionMinor) - c.Properties = start.ServerProperties - c.Locales = strings.Split(start.Locales, " ") - - // eventually support challenge/response here by also responding to - // connectionSecure. - auth, ok := pickSASLMechanism(config.SASL, strings.Split(start.Mechanisms, " ")) - if !ok { - return ErrSASL - } - - // Save this mechanism off as the one we chose - c.Config.SASL = []Authentication{auth} - - // Set the connection locale to client locale - c.Config.Locale = config.Locale - - return c.openTune(config, auth) -} - -func (c *Connection) openTune(config Config, auth Authentication) error { - if len(config.Properties) == 0 { - config.Properties = NewConnectionProperties() - } - - config.Properties["capabilities"] = Table{ - "connection.blocked": true, - "consumer_cancel_notify": true, - "basic.nack": true, - "publisher_confirms": true, - } - - ok := &connectionStartOk{ - ClientProperties: config.Properties, - Mechanism: auth.Mechanism(), - Response: auth.Response(), - Locale: config.Locale, - } - tune := &connectionTune{} - - if err := c.call(ok, tune); err != nil { - // per spec, a connection can only be closed when it has been opened - // so at this point, we know it's an auth error, but the socket - // was closed instead. Return a meaningful error. - return ErrCredentials - } - - // Edge case that may race with c.shutdown() - // https://github.com/rabbitmq/amqp091-go/issues/170 - c.m.Lock() - - // When the server and client both use default 0, then the max channel is - // only limited by uint16. - c.Config.ChannelMax = pick(config.ChannelMax, int(tune.ChannelMax)) - if c.Config.ChannelMax == 0 { - c.Config.ChannelMax = defaultChannelMax - } - c.Config.ChannelMax = min(c.Config.ChannelMax, maxChannelMax) - - c.allocator = newAllocator(1, c.Config.ChannelMax) - - c.m.Unlock() - - // Frame size includes headers and end byte (len(payload)+8), even if - // this is less than FrameMinSize, use what the server sends because the - // alternative is to stop the handshake here. - c.Config.FrameSize = pick(config.FrameSize, int(tune.FrameMax)) - - // Save this off for resetDeadline() - c.Config.Heartbeat = time.Second * time.Duration(pick( - int(config.Heartbeat/time.Second), - int(tune.Heartbeat))) - - // "The client should start sending heartbeats after receiving a - // Connection.Tune method" - go c.heartbeater(c.Config.Heartbeat/2, c.NotifyClose(make(chan *Error, 1))) - - if err := c.send(&methodFrame{ - ChannelId: 0, - Method: &connectionTuneOk{ - ChannelMax: uint16(c.Config.ChannelMax), - FrameMax: uint32(c.Config.FrameSize), - Heartbeat: uint16(c.Config.Heartbeat / time.Second), - }, - }); err != nil { - return err - } - - return c.openVhost(config) -} - -func (c *Connection) openVhost(config Config) error { - req := &connectionOpen{VirtualHost: config.Vhost} - res := &connectionOpenOk{} - - if err := c.call(req, res); err != nil { - // Cannot be closed yet, but we know it's a vhost problem - return ErrVhost - } - - c.Config.Vhost = config.Vhost - - return c.openComplete() -} - -// openComplete performs any final Connection initialization dependent on the -// connection handshake and clears any state needed for TLS and AMQP handshaking. -func (c *Connection) openComplete() error { - // We clear the deadlines and let the heartbeater reset the read deadline if requested. - // RabbitMQ uses TCP flow control at this point for pushback so Writes can - // intentionally block. - if deadliner, ok := c.conn.(interface { - SetDeadline(time.Time) error - }); ok { - _ = deadliner.SetDeadline(time.Time{}) - } - - return nil -} - -// tlsConfigFromURI tries to create TLS configuration based on query parameters. -// Returns default (empty) config in case no suitable client cert and/or client key not provided. -// Returns error in case certificates can not be parsed. -func tlsConfigFromURI(uri URI) (*tls.Config, error) { - var certPool *x509.CertPool - if uri.CACertFile != "" { - data, err := os.ReadFile(uri.CACertFile) - if err != nil { - return nil, fmt.Errorf("read CA certificate: %w", err) - } - - certPool = x509.NewCertPool() - certPool.AppendCertsFromPEM(data) - } else if sysPool, err := x509.SystemCertPool(); err != nil { - return nil, fmt.Errorf("load system certificates: %w", err) - } else { - certPool = sysPool - } - - if uri.CertFile == "" || uri.KeyFile == "" { - // no client auth (mTLS), just server auth - return &tls.Config{ - RootCAs: certPool, - ServerName: uri.ServerName, - }, nil - } - - certificate, err := tls.LoadX509KeyPair(uri.CertFile, uri.KeyFile) - if err != nil { - return nil, fmt.Errorf("load client certificate: %w", err) - } - - return &tls.Config{ - Certificates: []tls.Certificate{certificate}, - RootCAs: certPool, - ServerName: uri.ServerName, - }, nil -} - -func max(a, b int) int { - if a > b { - return a - } - return b -} - -func min(a, b int) int { - if a < b { - return a - } - return b -} - -func pick(client, server int) int { - if client == 0 || server == 0 { - return max(client, server) - } - return min(client, server) -} diff --git a/vendor/github.com/rabbitmq/amqp091-go/consumers.go b/vendor/github.com/rabbitmq/amqp091-go/consumers.go deleted file mode 100644 index c352fec..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/consumers.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. -// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package amqp091 - -import ( - "os" - "strconv" - "sync" - "sync/atomic" -) - -var consumerSeq uint64 - -const consumerTagLengthMax = 0xFF // see writeShortstr - -func uniqueConsumerTag() string { - return commandNameBasedUniqueConsumerTag(os.Args[0]) -} - -func commandNameBasedUniqueConsumerTag(commandName string) string { - tagPrefix := "ctag-" - tagInfix := commandName - tagSuffix := "-" + strconv.FormatUint(atomic.AddUint64(&consumerSeq, 1), 10) - - if len(tagPrefix)+len(tagInfix)+len(tagSuffix) > consumerTagLengthMax { - tagInfix = "streadway/amqp" - } - - return tagPrefix + tagInfix + tagSuffix -} - -type consumerBuffers map[string]chan *Delivery - -// Concurrent type that manages the consumerTag -> -// ingress consumerBuffer mapping -type consumers struct { - sync.WaitGroup // one for buffer - closed chan struct{} // signal buffer - - sync.Mutex // protects below - chans consumerBuffers -} - -func makeConsumers() *consumers { - return &consumers{ - closed: make(chan struct{}), - chans: make(consumerBuffers), - } -} - -func (subs *consumers) buffer(in chan *Delivery, out chan Delivery) { - defer close(out) - defer subs.Done() - - var inflight = in - var queue []*Delivery - - for delivery := range in { - queue = append(queue, delivery) - - for len(queue) > 0 { - select { - case <-subs.closed: - // closed before drained, drop in-flight - return - - case delivery, consuming := <-inflight: - if consuming { - queue = append(queue, delivery) - } else { - inflight = nil - } - - case out <- *queue[0]: - /* - * https://github.com/rabbitmq/amqp091-go/issues/179 - * https://github.com/rabbitmq/amqp091-go/pull/180 - * - * Comment from @lars-t-hansen: - * - * Given Go's slice semantics, and barring any information - * available to the compiler that proves that queue is the only - * pointer to the memory it references, the only meaning that - * queue = queue[1:] can have is basically queue += sizeof(queue - * element), ie, it bumps a pointer. Looking at the generated - * code for a simple example (on ARM64 in this case) bears this - * out. So what we're left with is an array that we have a - * pointer into the middle of. When the GC traces this pointer, - * it too does not know whether the array has multiple - * referents, and so its only sensible choice is to find the - * beginning of the array, and if the array is not already - * visited, mark every element in it, including the "dead" - * pointer. - * - * (Depending on the program dynamics, an element may eventually - * be appended to the queue when the queue is at capacity, and - * in this case the live elements are copied into a new array - * and the old array is left to be GC'd eventually, along with - * the dead object. But that can take time.) - */ - queue[0] = nil - queue = queue[1:] - } - } - } -} - -// On key conflict, close the previous channel. -func (subs *consumers) add(tag string, consumer chan Delivery) { - subs.Lock() - defer subs.Unlock() - - if prev, found := subs.chans[tag]; found { - close(prev) - } - - in := make(chan *Delivery) - subs.chans[tag] = in - - subs.Add(1) - go subs.buffer(in, consumer) -} - -func (subs *consumers) cancel(tag string) (found bool) { - subs.Lock() - defer subs.Unlock() - - ch, found := subs.chans[tag] - - if found { - delete(subs.chans, tag) - close(ch) - } - - return found -} - -func (subs *consumers) close() { - subs.Lock() - defer subs.Unlock() - - close(subs.closed) - - for tag, ch := range subs.chans { - delete(subs.chans, tag) - close(ch) - } - - subs.Wait() -} - -// Sends a delivery to a the consumer identified by `tag`. -// If unbuffered channels are used for Consume this method -// could block all deliveries until the consumer -// receives on the other end of the channel. -func (subs *consumers) send(tag string, msg *Delivery) bool { - subs.Lock() - defer subs.Unlock() - - buffer, found := subs.chans[tag] - if found { - buffer <- msg - } - - return found -} diff --git a/vendor/github.com/rabbitmq/amqp091-go/delivery.go b/vendor/github.com/rabbitmq/amqp091-go/delivery.go deleted file mode 100644 index e94cf34..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/delivery.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. -// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package amqp091 - -import ( - "errors" - "time" -) - -var errDeliveryNotInitialized = errors.New("delivery not initialized") - -// Acknowledger notifies the server of successful or failed consumption of -// deliveries via identifier found in the Delivery.DeliveryTag field. -// -// Applications can provide mock implementations in tests of Delivery handlers. -type Acknowledger interface { - Ack(tag uint64, multiple bool) error - Nack(tag uint64, multiple bool, requeue bool) error - Reject(tag uint64, requeue bool) error -} - -// Delivery captures the fields for a previously delivered message resident in -// a queue to be delivered by the server to a consumer from Channel.Consume or -// Channel.Get. -type Delivery struct { - Acknowledger Acknowledger // the channel from which this delivery arrived - - Headers Table // Application or header exchange table - - // Properties - ContentType string // MIME content type - ContentEncoding string // MIME content encoding - DeliveryMode uint8 // queue implementation use - non-persistent (1) or persistent (2) - Priority uint8 // queue implementation use - 0 to 9 - CorrelationId string // application use - correlation identifier - ReplyTo string // application use - address to reply to (ex: RPC) - Expiration string // implementation use - message expiration spec - MessageId string // application use - message identifier - Timestamp time.Time // application use - message timestamp - Type string // application use - message type name - UserId string // application use - creating user - should be authenticated user - AppId string // application use - creating application id - - // Valid only with Channel.Consume - ConsumerTag string - - // Valid only with Channel.Get - MessageCount uint32 - - DeliveryTag uint64 - Redelivered bool - Exchange string // basic.publish exchange - RoutingKey string // basic.publish routing key - - Body []byte -} - -func newDelivery(channel *Channel, msg messageWithContent) *Delivery { - props, body := msg.getContent() - - delivery := Delivery{ - Acknowledger: channel, - - Headers: props.Headers, - ContentType: props.ContentType, - ContentEncoding: props.ContentEncoding, - DeliveryMode: props.DeliveryMode, - Priority: props.Priority, - CorrelationId: props.CorrelationId, - ReplyTo: props.ReplyTo, - Expiration: props.Expiration, - MessageId: props.MessageId, - Timestamp: props.Timestamp, - Type: props.Type, - UserId: props.UserId, - AppId: props.AppId, - - Body: body, - } - - // Properties for the delivery types - switch m := msg.(type) { - case *basicDeliver: - delivery.ConsumerTag = m.ConsumerTag - delivery.DeliveryTag = m.DeliveryTag - delivery.Redelivered = m.Redelivered - delivery.Exchange = m.Exchange - delivery.RoutingKey = m.RoutingKey - - case *basicGetOk: - delivery.MessageCount = m.MessageCount - delivery.DeliveryTag = m.DeliveryTag - delivery.Redelivered = m.Redelivered - delivery.Exchange = m.Exchange - delivery.RoutingKey = m.RoutingKey - } - - return &delivery -} - -/* -Ack delegates an acknowledgement through the Acknowledger interface that the -client or server has finished work on a delivery. - -All deliveries in AMQP must be acknowledged. If you called Channel.Consume -with autoAck true then the server will be automatically ack each message and -this method should not be called. Otherwise, you must call Delivery.Ack after -you have successfully processed this delivery. - -When multiple is true, this delivery and all prior unacknowledged deliveries -on the same channel will be acknowledged. This is useful for batch processing -of deliveries. - -An error will indicate that the acknowledge could not be delivered to the -channel it was sent from. - -Either Delivery.Ack, Delivery.Reject or Delivery.Nack must be called for every -delivery that is not automatically acknowledged. -*/ -func (d Delivery) Ack(multiple bool) error { - if d.Acknowledger == nil { - return errDeliveryNotInitialized - } - return d.Acknowledger.Ack(d.DeliveryTag, multiple) -} - -/* -Reject delegates a negatively acknowledgement through the Acknowledger interface. - -When requeue is true, queue this message to be delivered to a consumer on a -different channel. When requeue is false or the server is unable to queue this -message, it will be dropped. - -If you are batch processing deliveries, and your server supports it, prefer -Delivery.Nack. - -Either Delivery.Ack, Delivery.Reject or Delivery.Nack must be called for every -delivery that is not automatically acknowledged. -*/ -func (d Delivery) Reject(requeue bool) error { - if d.Acknowledger == nil { - return errDeliveryNotInitialized - } - return d.Acknowledger.Reject(d.DeliveryTag, requeue) -} - -/* -Nack negatively acknowledge the delivery of message(s) identified by the -delivery tag from either the client or server. - -When multiple is true, nack messages up to and including delivered messages up -until the delivery tag delivered on the same channel. - -When requeue is true, request the server to deliver this message to a different -consumer. If it is not possible or requeue is false, the message will be -dropped or delivered to a server configured dead-letter queue. - -This method must not be used to select or requeue messages the client wishes -not to handle, rather it is to inform the server that the client is incapable -of handling this message at this time. - -Either Delivery.Ack, Delivery.Reject or Delivery.Nack must be called for every -delivery that is not automatically acknowledged. -*/ -func (d Delivery) Nack(multiple, requeue bool) error { - if d.Acknowledger == nil { - return errDeliveryNotInitialized - } - return d.Acknowledger.Nack(d.DeliveryTag, multiple, requeue) -} diff --git a/vendor/github.com/rabbitmq/amqp091-go/doc.go b/vendor/github.com/rabbitmq/amqp091-go/doc.go deleted file mode 100644 index 8cb0b64..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/doc.go +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. -// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* -Package amqp091 is an AMQP 0.9.1 client with RabbitMQ extensions - -Understand the AMQP 0.9.1 messaging model by reviewing these links first. Much -of the terminology in this library directly relates to AMQP concepts. - - Resources - - http://www.rabbitmq.com/tutorials/amqp-concepts.html - http://www.rabbitmq.com/getstarted.html - http://www.rabbitmq.com/amqp-0-9-1-reference.html - -# Design - -Most other broker clients publish to queues, but in AMQP, clients publish -Exchanges instead. AMQP is programmable, meaning that both the producers and -consumers agree on the configuration of the broker, instead of requiring an -operator or system configuration that declares the logical topology in the -broker. The routing between producers and consumer queues is via Bindings. -These bindings form the logical topology of the broker. - -In this library, a message sent from publisher is called a "Publishing" and a -message received to a consumer is called a "Delivery". The fields of -Publishings and Deliveries are close but not exact mappings to the underlying -wire format to maintain stronger types. Many other libraries will combine -message properties with message headers. In this library, the message well -known properties are strongly typed fields on the Publishings and Deliveries, -whereas the user defined headers are in the Headers field. - -The method naming closely matches the protocol's method name with positional -parameters mapping to named protocol message fields. The motivation here is to -present a comprehensive view over all possible interactions with the server. - -Generally, methods that map to protocol methods of the "basic" class will be -elided in this interface, and "select" methods of various channel mode selectors -will be elided for example Channel.Confirm and Channel.Tx. - -The library is intentionally designed to be synchronous, where responses for -each protocol message are required to be received in an RPC manner. Some -methods have a noWait parameter like Channel.QueueDeclare, and some methods are -asynchronous like Channel.Publish. The error values should still be checked for -these methods as they will indicate IO failures like when the underlying -connection closes. - -# Asynchronous Events - -Clients of this library may be interested in receiving some of the protocol -messages other than Deliveries like basic.ack methods while a channel is in -confirm mode. - -The Notify* methods with Connection and Channel receivers model the pattern of -asynchronous events like closes due to exceptions, or messages that are sent out -of band from an RPC call like basic.ack or basic.flow. - -Any asynchronous events, including Deliveries and Publishings must always have -a receiver until the corresponding chans are closed. Without asynchronous -receivers, the synchronous methods will block. - -# Use Case - -It's important as a client to an AMQP topology to ensure the state of the -broker matches your expectations. For both publish and consume use cases, -make sure you declare the queues, exchanges and bindings you expect to exist -prior to calling [Channel.PublishWithContext] or [Channel.Consume]. - - // Connections start with amqp.Dial() typically from a command line argument - // or environment variable. - connection, err := amqp.Dial(os.Getenv("AMQP_URL")) - - // To cleanly shutdown by flushing kernel buffers, make sure to close and - // wait for the response. - defer connection.Close() - - // Most operations happen on a channel. If any error is returned on a - // channel, the channel will no longer be valid, throw it away and try with - // a different channel. If you use many channels, it's useful for the - // server to - channel, err := connection.Channel() - - // Declare your topology here, if it doesn't exist, it will be created, if - // it existed already and is not what you expect, then that's considered an - // error. - - // Use your connection on this topology with either Publish or Consume, or - // inspect your queues with QueueInspect. It's unwise to mix Publish and - // Consume to let TCP do its job well. - -# SSL/TLS - Secure connections - -When Dial encounters an amqps:// scheme, it will use the zero value of a -tls.Config. This will only perform server certificate and host verification. - -Use DialTLS when you wish to provide a client certificate (recommended), -include a private certificate authority's certificate in the cert chain for -server validity, or run insecure by not verifying the server certificate dial -your own connection. DialTLS will use the provided tls.Config when it -encounters an amqps:// scheme and will dial a plain connection when it -encounters an amqp:// scheme. - -SSL/TLS in RabbitMQ is documented here: http://www.rabbitmq.com/ssl.html - -# Best practises for Connection and Channel notifications: - -In order to be notified when a connection or channel gets closed, both -structures offer the possibility to register channels using -[Channel.NotifyClose] and [Connection.NotifyClose] functions: - - notifyConnCloseCh := conn.NotifyClose(make(chan *amqp.Error)) - -No errors will be sent in case of a graceful connection close. In case of a -non-graceful closure due to e.g. network issue, or forced connection closure -from the Management UI, the error will be notified synchronously by the library. - -The error is sent synchronously to the channel, so that the flow will wait until -the receiver consumes from the channel. To avoid deadlocks in the library, it is -necessary to consume from the channels. This could be done inside a -different goroutine with a select listening on the two channels inside a for -loop like: - - go func() { - for notifyConnClose != nil || notifyChanClose != nil { - select { - case err, ok := <-notifyConnClose: - if !ok { - notifyConnClose = nil - } else { - fmt.Printf("connection closed, error %s", err) - } - case err, ok := <-notifyChanClose: - if !ok { - notifyChanClose = nil - } else { - fmt.Printf("channel closed, error %s", err) - } - } - } - }() - -Another approach is to use buffered channels: - - notifyConnCloseCh := conn.NotifyClose(make(chan *amqp.Error, 1)) - -The library sends to notification channels just once. After sending a notification -to all channels, the library closes all registered notification channels. After -receiving a notification, the application should create and register a new channel. - -# Best practises for NotifyPublish notifications: - -Using [Channel.NotifyPublish] allows the caller of the library to be notified, -through a go channel, when a message has been received and confirmed by the -broker. It's advisable to wait for all Confirmations to arrive before calling -[Channel.Close] or [Connection.Close]. It is also necessary to consume from this -channel until it gets closed. The library sends synchronously to the registered channel. -It is advisable to use a buffered channel, with capacity set to the maximum acceptable -number of unconfirmed messages. - -It is important to consume from the confirmation channel at all times, in order to avoid -deadlocks in the library. -*/ -package amqp091 diff --git a/vendor/github.com/rabbitmq/amqp091-go/fuzz.go b/vendor/github.com/rabbitmq/amqp091-go/fuzz.go deleted file mode 100644 index c9f03ea..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/fuzz.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. -// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gofuzz -// +build gofuzz - -package amqp091 - -import "bytes" - -func Fuzz(data []byte) int { - r := reader{bytes.NewReader(data)} - frame, err := r.ReadFrame() - if err != nil { - if frame != nil { - panic("frame is not nil") - } - return 0 - } - return 1 -} diff --git a/vendor/github.com/rabbitmq/amqp091-go/gen.sh b/vendor/github.com/rabbitmq/amqp091-go/gen.sh deleted file mode 100644 index d46e19b..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/gen.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -go run spec/gen.go < spec/amqp0-9-1.stripped.extended.xml | gofmt > spec091.go diff --git a/vendor/github.com/rabbitmq/amqp091-go/log.go b/vendor/github.com/rabbitmq/amqp091-go/log.go deleted file mode 100644 index 7540f13..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/log.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2022 VMware, Inc. or its affiliates. All Rights Reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package amqp091 - -type Logging interface { - Printf(format string, v ...interface{}) -} - -var Logger Logging = NullLogger{} - -// Enables logging using a custom Logging instance. Note that this is -// not thread safe and should be called at application start -func SetLogger(logger Logging) { - Logger = logger -} - -type NullLogger struct { -} - -func (l NullLogger) Printf(format string, v ...interface{}) { -} diff --git a/vendor/github.com/rabbitmq/amqp091-go/read.go b/vendor/github.com/rabbitmq/amqp091-go/read.go deleted file mode 100644 index a8bed13..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/read.go +++ /dev/null @@ -1,450 +0,0 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. -// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package amqp091 - -import ( - "bytes" - "encoding/binary" - "errors" - "io" - "time" -) - -/* -ReadFrame reads a frame from an input stream and returns an interface that can be cast into -one of the following: - - methodFrame - PropertiesFrame - bodyFrame - heartbeatFrame - -2.3.5 frame Details - -All frames consist of a header (7 octets), a payload of arbitrary size, and a -'frame-end' octet that detects malformed frames: - - 0 1 3 7 size+7 size+8 - +------+---------+-------------+ +------------+ +-----------+ - | type | channel | size | | payload | | frame-end | - +------+---------+-------------+ +------------+ +-----------+ - octet short long size octets octet - -To read a frame, we: - 1. Read the header and check the frame type and channel. - 2. Depending on the frame type, we read the payload and process it. - 3. Read the frame end octet. - -In realistic implementations where performance is a concern, we would use -“read-ahead buffering” or - -“gathering reads” to avoid doing three separate system calls to read a frame. -*/ -func (r *reader) ReadFrame() (frame frame, err error) { - var scratch [7]byte - - if _, err = io.ReadFull(r.r, scratch[:7]); err != nil { - return - } - - typ := scratch[0] - channel := binary.BigEndian.Uint16(scratch[1:3]) - size := binary.BigEndian.Uint32(scratch[3:7]) - - switch typ { - case frameMethod: - if frame, err = r.parseMethodFrame(channel, size); err != nil { - return - } - - case frameHeader: - if frame, err = r.parseHeaderFrame(channel, size); err != nil { - return - } - - case frameBody: - if frame, err = r.parseBodyFrame(channel, size); err != nil { - return nil, err - } - - case frameHeartbeat: - if frame, err = r.parseHeartbeatFrame(channel, size); err != nil { - return - } - - default: - return nil, ErrFrame - } - - if _, err = io.ReadFull(r.r, scratch[:1]); err != nil { - return nil, err - } - - if scratch[0] != frameEnd { - return nil, ErrFrame - } - - return -} - -func readShortstr(r io.Reader) (v string, err error) { - var length uint8 - if err = binary.Read(r, binary.BigEndian, &length); err != nil { - return - } - - bytes := make([]byte, length) - if _, err = io.ReadFull(r, bytes); err != nil { - return - } - return string(bytes), nil -} - -func readLongstr(r io.Reader) (v string, err error) { - var length uint32 - if err = binary.Read(r, binary.BigEndian, &length); err != nil { - return - } - - // slices can't be longer than max int32 value - if length > (^uint32(0) >> 1) { - return - } - - bytes := make([]byte, length) - if _, err = io.ReadFull(r, bytes); err != nil { - return - } - return string(bytes), nil -} - -func readDecimal(r io.Reader) (v Decimal, err error) { - if err = binary.Read(r, binary.BigEndian, &v.Scale); err != nil { - return - } - if err = binary.Read(r, binary.BigEndian, &v.Value); err != nil { - return - } - return -} - -func readTimestamp(r io.Reader) (v time.Time, err error) { - var sec int64 - if err = binary.Read(r, binary.BigEndian, &sec); err != nil { - return - } - return time.Unix(sec, 0), nil -} - -/* -'A': []interface{} -'D': Decimal -'F': Table -'I': int32 -'S': string -'T': time.Time -'V': nil -'b': int8 -'B': byte -'d': float64 -'f': float32 -'l': int64 -'s': int16 -'t': bool -'x': []byte -*/ -func readField(r io.Reader) (v interface{}, err error) { - var typ byte - if err = binary.Read(r, binary.BigEndian, &typ); err != nil { - return - } - - switch typ { - case 't': - var value uint8 - if err = binary.Read(r, binary.BigEndian, &value); err != nil { - return - } - return value != 0, nil - - case 'B': - var value [1]byte - if _, err = io.ReadFull(r, value[0:1]); err != nil { - return - } - return value[0], nil - - case 'b': - var value int8 - if err = binary.Read(r, binary.BigEndian, &value); err != nil { - return - } - return value, nil - - case 's': - var value int16 - if err = binary.Read(r, binary.BigEndian, &value); err != nil { - return - } - return value, nil - - case 'I': - var value int32 - if err = binary.Read(r, binary.BigEndian, &value); err != nil { - return - } - return value, nil - - case 'l': - var value int64 - if err = binary.Read(r, binary.BigEndian, &value); err != nil { - return - } - return value, nil - - case 'f': - var value float32 - if err = binary.Read(r, binary.BigEndian, &value); err != nil { - return - } - return value, nil - - case 'd': - var value float64 - if err = binary.Read(r, binary.BigEndian, &value); err != nil { - return - } - return value, nil - - case 'D': - return readDecimal(r) - - case 'S': - return readLongstr(r) - - case 'A': - return readArray(r) - - case 'T': - return readTimestamp(r) - - case 'F': - return readTable(r) - - case 'x': - var len int32 - if err = binary.Read(r, binary.BigEndian, &len); err != nil { - return nil, err - } - - value := make([]byte, len) - if _, err = io.ReadFull(r, value); err != nil { - return nil, err - } - return value, err - - case 'V': - return nil, nil - } - - return nil, ErrSyntax -} - -/* -Field tables are long strings that contain packed name-value pairs. The -name-value pairs are encoded as short string defining the name, and octet -defining the values type and then the value itself. The valid field types for -tables are an extension of the native integer, bit, string, and timestamp -types, and are shown in the grammar. Multi-octet integer fields are always -held in network byte order. -*/ -func readTable(r io.Reader) (table Table, err error) { - var nested bytes.Buffer - var str string - - if str, err = readLongstr(r); err != nil { - return - } - - nested.Write([]byte(str)) - - table = make(Table) - - for nested.Len() > 0 { - var key string - var value interface{} - - if key, err = readShortstr(&nested); err != nil { - return - } - - if value, err = readField(&nested); err != nil { - return - } - - table[key] = value - } - - return -} - -func readArray(r io.Reader) ([]interface{}, error) { - var ( - size uint32 - err error - ) - - if err = binary.Read(r, binary.BigEndian, &size); err != nil { - return nil, err - } - - var ( - lim = &io.LimitedReader{R: r, N: int64(size)} - arr []interface{} - field interface{} - ) - - for { - if field, err = readField(lim); err != nil { - if err == io.EOF { - break - } - return nil, err - } - arr = append(arr, field) - } - - return arr, nil -} - -// Checks if this bit mask matches the flags bitset -func hasProperty(mask uint16, prop int) bool { - return int(mask)&prop > 0 -} - -func (r *reader) parseHeaderFrame(channel uint16, size uint32) (frame frame, err error) { - hf := &headerFrame{ - ChannelId: channel, - } - - if err = binary.Read(r.r, binary.BigEndian, &hf.ClassId); err != nil { - return - } - - if err = binary.Read(r.r, binary.BigEndian, &hf.weight); err != nil { - return - } - - if err = binary.Read(r.r, binary.BigEndian, &hf.Size); err != nil { - return - } - - var flags uint16 - - if err = binary.Read(r.r, binary.BigEndian, &flags); err != nil { - return - } - - if hasProperty(flags, flagContentType) { - if hf.Properties.ContentType, err = readShortstr(r.r); err != nil { - return - } - } - if hasProperty(flags, flagContentEncoding) { - if hf.Properties.ContentEncoding, err = readShortstr(r.r); err != nil { - return - } - } - if hasProperty(flags, flagHeaders) { - if hf.Properties.Headers, err = readTable(r.r); err != nil { - return - } - } - if hasProperty(flags, flagDeliveryMode) { - if err = binary.Read(r.r, binary.BigEndian, &hf.Properties.DeliveryMode); err != nil { - return - } - } - if hasProperty(flags, flagPriority) { - if err = binary.Read(r.r, binary.BigEndian, &hf.Properties.Priority); err != nil { - return - } - } - if hasProperty(flags, flagCorrelationId) { - if hf.Properties.CorrelationId, err = readShortstr(r.r); err != nil { - return - } - } - if hasProperty(flags, flagReplyTo) { - if hf.Properties.ReplyTo, err = readShortstr(r.r); err != nil { - return - } - } - if hasProperty(flags, flagExpiration) { - if hf.Properties.Expiration, err = readShortstr(r.r); err != nil { - return - } - } - if hasProperty(flags, flagMessageId) { - if hf.Properties.MessageId, err = readShortstr(r.r); err != nil { - return - } - } - if hasProperty(flags, flagTimestamp) { - if hf.Properties.Timestamp, err = readTimestamp(r.r); err != nil { - return - } - } - if hasProperty(flags, flagType) { - if hf.Properties.Type, err = readShortstr(r.r); err != nil { - return - } - } - if hasProperty(flags, flagUserId) { - if hf.Properties.UserId, err = readShortstr(r.r); err != nil { - return - } - } - if hasProperty(flags, flagAppId) { - if hf.Properties.AppId, err = readShortstr(r.r); err != nil { - return - } - } - if hasProperty(flags, flagReserved1) { - if hf.Properties.reserved1, err = readShortstr(r.r); err != nil { - return - } - } - - return hf, nil -} - -func (r *reader) parseBodyFrame(channel uint16, size uint32) (frame frame, err error) { - bf := &bodyFrame{ - ChannelId: channel, - Body: make([]byte, size), - } - - if _, err = io.ReadFull(r.r, bf.Body); err != nil { - return nil, err - } - - return bf, nil -} - -var errHeartbeatPayload = errors.New("Heartbeats should not have a payload") - -func (r *reader) parseHeartbeatFrame(channel uint16, size uint32) (frame frame, err error) { - hf := &heartbeatFrame{ - ChannelId: channel, - } - - if size > 0 { - return nil, errHeartbeatPayload - } - - return hf, nil -} diff --git a/vendor/github.com/rabbitmq/amqp091-go/return.go b/vendor/github.com/rabbitmq/amqp091-go/return.go deleted file mode 100644 index cdc3875..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/return.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. -// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package amqp091 - -import ( - "time" -) - -// Return captures a flattened struct of fields returned by the server when a -// Publishing is unable to be delivered either due to the `mandatory` flag set -// and no route found, or `immediate` flag set and no free consumer. -type Return struct { - ReplyCode uint16 // reason - ReplyText string // description - Exchange string // basic.publish exchange - RoutingKey string // basic.publish routing key - - // Properties - ContentType string // MIME content type - ContentEncoding string // MIME content encoding - Headers Table // Application or header exchange table - DeliveryMode uint8 // queue implementation use - non-persistent (1) or persistent (2) - Priority uint8 // queue implementation use - 0 to 9 - CorrelationId string // application use - correlation identifier - ReplyTo string // application use - address to to reply to (ex: RPC) - Expiration string // implementation use - message expiration spec - MessageId string // application use - message identifier - Timestamp time.Time // application use - message timestamp - Type string // application use - message type name - UserId string // application use - creating user id - AppId string // application use - creating application - - Body []byte -} - -func newReturn(msg basicReturn) *Return { - props, body := msg.getContent() - - return &Return{ - ReplyCode: msg.ReplyCode, - ReplyText: msg.ReplyText, - Exchange: msg.Exchange, - RoutingKey: msg.RoutingKey, - - Headers: props.Headers, - ContentType: props.ContentType, - ContentEncoding: props.ContentEncoding, - DeliveryMode: props.DeliveryMode, - Priority: props.Priority, - CorrelationId: props.CorrelationId, - ReplyTo: props.ReplyTo, - Expiration: props.Expiration, - MessageId: props.MessageId, - Timestamp: props.Timestamp, - Type: props.Type, - UserId: props.UserId, - AppId: props.AppId, - - Body: body, - } -} diff --git a/vendor/github.com/rabbitmq/amqp091-go/spec091.go b/vendor/github.com/rabbitmq/amqp091-go/spec091.go deleted file mode 100644 index d86e753..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/spec091.go +++ /dev/null @@ -1,3382 +0,0 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. -// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* GENERATED FILE - DO NOT EDIT */ -/* Rebuild from the spec/gen.go tool */ - -package amqp091 - -import ( - "encoding/binary" - "fmt" - "io" -) - -// Error codes that can be sent from the server during a connection or -// channel exception or used by the client to indicate a class of error like -// ErrCredentials. The text of the error is likely more interesting than -// these constants. -const ( - frameMethod = 1 - frameHeader = 2 - frameBody = 3 - frameHeartbeat = 8 - frameMinSize = 4096 - frameEnd = 206 - replySuccess = 200 - ContentTooLarge = 311 - NoRoute = 312 - NoConsumers = 313 - ConnectionForced = 320 - InvalidPath = 402 - AccessRefused = 403 - NotFound = 404 - ResourceLocked = 405 - PreconditionFailed = 406 - FrameError = 501 - SyntaxError = 502 - CommandInvalid = 503 - ChannelError = 504 - UnexpectedFrame = 505 - ResourceError = 506 - NotAllowed = 530 - NotImplemented = 540 - InternalError = 541 -) - -func isSoftExceptionCode(code int) bool { - switch code { - case 311: - return true - case 312: - return true - case 313: - return true - case 403: - return true - case 404: - return true - case 405: - return true - case 406: - return true - - } - return false -} - -type connectionStart struct { - VersionMajor byte - VersionMinor byte - ServerProperties Table - Mechanisms string - Locales string -} - -func (msg *connectionStart) id() (uint16, uint16) { - return 10, 10 -} - -func (msg *connectionStart) wait() bool { - return true -} - -func (msg *connectionStart) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, msg.VersionMajor); err != nil { - return - } - if err = binary.Write(w, binary.BigEndian, msg.VersionMinor); err != nil { - return - } - - if err = writeTable(w, msg.ServerProperties); err != nil { - return - } - - if err = writeLongstr(w, msg.Mechanisms); err != nil { - return - } - if err = writeLongstr(w, msg.Locales); err != nil { - return - } - - return -} - -func (msg *connectionStart) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &msg.VersionMajor); err != nil { - return - } - if err = binary.Read(r, binary.BigEndian, &msg.VersionMinor); err != nil { - return - } - - if msg.ServerProperties, err = readTable(r); err != nil { - return - } - - if msg.Mechanisms, err = readLongstr(r); err != nil { - return - } - if msg.Locales, err = readLongstr(r); err != nil { - return - } - - return -} - -type connectionStartOk struct { - ClientProperties Table - Mechanism string - Response string - Locale string -} - -func (msg *connectionStartOk) id() (uint16, uint16) { - return 10, 11 -} - -func (msg *connectionStartOk) wait() bool { - return true -} - -func (msg *connectionStartOk) write(w io.Writer) (err error) { - - if err = writeTable(w, msg.ClientProperties); err != nil { - return - } - - if err = writeShortstr(w, msg.Mechanism); err != nil { - return - } - - if err = writeLongstr(w, msg.Response); err != nil { - return - } - - if err = writeShortstr(w, msg.Locale); err != nil { - return - } - - return -} - -func (msg *connectionStartOk) read(r io.Reader) (err error) { - - if msg.ClientProperties, err = readTable(r); err != nil { - return - } - - if msg.Mechanism, err = readShortstr(r); err != nil { - return - } - - if msg.Response, err = readLongstr(r); err != nil { - return - } - - if msg.Locale, err = readShortstr(r); err != nil { - return - } - - return -} - -type connectionSecure struct { - Challenge string -} - -func (msg *connectionSecure) id() (uint16, uint16) { - return 10, 20 -} - -func (msg *connectionSecure) wait() bool { - return true -} - -func (msg *connectionSecure) write(w io.Writer) (err error) { - - if err = writeLongstr(w, msg.Challenge); err != nil { - return - } - - return -} - -func (msg *connectionSecure) read(r io.Reader) (err error) { - - if msg.Challenge, err = readLongstr(r); err != nil { - return - } - - return -} - -type connectionSecureOk struct { - Response string -} - -func (msg *connectionSecureOk) id() (uint16, uint16) { - return 10, 21 -} - -func (msg *connectionSecureOk) wait() bool { - return true -} - -func (msg *connectionSecureOk) write(w io.Writer) (err error) { - - if err = writeLongstr(w, msg.Response); err != nil { - return - } - - return -} - -func (msg *connectionSecureOk) read(r io.Reader) (err error) { - - if msg.Response, err = readLongstr(r); err != nil { - return - } - - return -} - -type connectionTune struct { - ChannelMax uint16 - FrameMax uint32 - Heartbeat uint16 -} - -func (msg *connectionTune) id() (uint16, uint16) { - return 10, 30 -} - -func (msg *connectionTune) wait() bool { - return true -} - -func (msg *connectionTune) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, msg.ChannelMax); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, msg.FrameMax); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, msg.Heartbeat); err != nil { - return - } - - return -} - -func (msg *connectionTune) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &msg.ChannelMax); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &msg.FrameMax); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &msg.Heartbeat); err != nil { - return - } - - return -} - -type connectionTuneOk struct { - ChannelMax uint16 - FrameMax uint32 - Heartbeat uint16 -} - -func (msg *connectionTuneOk) id() (uint16, uint16) { - return 10, 31 -} - -func (msg *connectionTuneOk) wait() bool { - return true -} - -func (msg *connectionTuneOk) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, msg.ChannelMax); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, msg.FrameMax); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, msg.Heartbeat); err != nil { - return - } - - return -} - -func (msg *connectionTuneOk) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &msg.ChannelMax); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &msg.FrameMax); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &msg.Heartbeat); err != nil { - return - } - - return -} - -type connectionOpen struct { - VirtualHost string - reserved1 string - reserved2 bool -} - -func (msg *connectionOpen) id() (uint16, uint16) { - return 10, 40 -} - -func (msg *connectionOpen) wait() bool { - return true -} - -func (msg *connectionOpen) write(w io.Writer) (err error) { - var bits byte - - if err = writeShortstr(w, msg.VirtualHost); err != nil { - return - } - if err = writeShortstr(w, msg.reserved1); err != nil { - return - } - - if msg.reserved2 { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *connectionOpen) read(r io.Reader) (err error) { - var bits byte - - if msg.VirtualHost, err = readShortstr(r); err != nil { - return - } - if msg.reserved1, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.reserved2 = (bits&(1<<0) > 0) - - return -} - -type connectionOpenOk struct { - reserved1 string -} - -func (msg *connectionOpenOk) id() (uint16, uint16) { - return 10, 41 -} - -func (msg *connectionOpenOk) wait() bool { - return true -} - -func (msg *connectionOpenOk) write(w io.Writer) (err error) { - - if err = writeShortstr(w, msg.reserved1); err != nil { - return - } - - return -} - -func (msg *connectionOpenOk) read(r io.Reader) (err error) { - - if msg.reserved1, err = readShortstr(r); err != nil { - return - } - - return -} - -type connectionClose struct { - ReplyCode uint16 - ReplyText string - ClassId uint16 - MethodId uint16 -} - -func (msg *connectionClose) id() (uint16, uint16) { - return 10, 50 -} - -func (msg *connectionClose) wait() bool { - return true -} - -func (msg *connectionClose) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, msg.ReplyCode); err != nil { - return - } - - if err = writeShortstr(w, msg.ReplyText); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, msg.ClassId); err != nil { - return - } - if err = binary.Write(w, binary.BigEndian, msg.MethodId); err != nil { - return - } - - return -} - -func (msg *connectionClose) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &msg.ReplyCode); err != nil { - return - } - - if msg.ReplyText, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &msg.ClassId); err != nil { - return - } - if err = binary.Read(r, binary.BigEndian, &msg.MethodId); err != nil { - return - } - - return -} - -type connectionCloseOk struct { -} - -func (msg *connectionCloseOk) id() (uint16, uint16) { - return 10, 51 -} - -func (msg *connectionCloseOk) wait() bool { - return true -} - -func (msg *connectionCloseOk) write(w io.Writer) (err error) { - - return -} - -func (msg *connectionCloseOk) read(r io.Reader) (err error) { - - return -} - -type connectionBlocked struct { - Reason string -} - -func (msg *connectionBlocked) id() (uint16, uint16) { - return 10, 60 -} - -func (msg *connectionBlocked) wait() bool { - return false -} - -func (msg *connectionBlocked) write(w io.Writer) (err error) { - - if err = writeShortstr(w, msg.Reason); err != nil { - return - } - - return -} - -func (msg *connectionBlocked) read(r io.Reader) (err error) { - - if msg.Reason, err = readShortstr(r); err != nil { - return - } - - return -} - -type connectionUnblocked struct { -} - -func (msg *connectionUnblocked) id() (uint16, uint16) { - return 10, 61 -} - -func (msg *connectionUnblocked) wait() bool { - return false -} - -func (msg *connectionUnblocked) write(w io.Writer) (err error) { - - return -} - -func (msg *connectionUnblocked) read(r io.Reader) (err error) { - - return -} - -type connectionUpdateSecret struct { - NewSecret string - Reason string -} - -func (msg *connectionUpdateSecret) id() (uint16, uint16) { - return 10, 70 -} - -func (msg *connectionUpdateSecret) wait() bool { - return true -} - -func (msg *connectionUpdateSecret) write(w io.Writer) (err error) { - - if err = writeLongstr(w, msg.NewSecret); err != nil { - return - } - - if err = writeShortstr(w, msg.Reason); err != nil { - return - } - - return -} - -func (msg *connectionUpdateSecret) read(r io.Reader) (err error) { - - if msg.NewSecret, err = readLongstr(r); err != nil { - return - } - - if msg.Reason, err = readShortstr(r); err != nil { - return - } - - return -} - -type connectionUpdateSecretOk struct { -} - -func (msg *connectionUpdateSecretOk) id() (uint16, uint16) { - return 10, 71 -} - -func (msg *connectionUpdateSecretOk) wait() bool { - return true -} - -func (msg *connectionUpdateSecretOk) write(w io.Writer) (err error) { - - return -} - -func (msg *connectionUpdateSecretOk) read(r io.Reader) (err error) { - - return -} - -type channelOpen struct { - reserved1 string -} - -func (msg *channelOpen) id() (uint16, uint16) { - return 20, 10 -} - -func (msg *channelOpen) wait() bool { - return true -} - -func (msg *channelOpen) write(w io.Writer) (err error) { - - if err = writeShortstr(w, msg.reserved1); err != nil { - return - } - - return -} - -func (msg *channelOpen) read(r io.Reader) (err error) { - - if msg.reserved1, err = readShortstr(r); err != nil { - return - } - - return -} - -type channelOpenOk struct { - reserved1 string -} - -func (msg *channelOpenOk) id() (uint16, uint16) { - return 20, 11 -} - -func (msg *channelOpenOk) wait() bool { - return true -} - -func (msg *channelOpenOk) write(w io.Writer) (err error) { - - if err = writeLongstr(w, msg.reserved1); err != nil { - return - } - - return -} - -func (msg *channelOpenOk) read(r io.Reader) (err error) { - - if msg.reserved1, err = readLongstr(r); err != nil { - return - } - - return -} - -type channelFlow struct { - Active bool -} - -func (msg *channelFlow) id() (uint16, uint16) { - return 20, 20 -} - -func (msg *channelFlow) wait() bool { - return true -} - -func (msg *channelFlow) write(w io.Writer) (err error) { - var bits byte - - if msg.Active { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *channelFlow) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.Active = (bits&(1<<0) > 0) - - return -} - -type channelFlowOk struct { - Active bool -} - -func (msg *channelFlowOk) id() (uint16, uint16) { - return 20, 21 -} - -func (msg *channelFlowOk) wait() bool { - return false -} - -func (msg *channelFlowOk) write(w io.Writer) (err error) { - var bits byte - - if msg.Active { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *channelFlowOk) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.Active = (bits&(1<<0) > 0) - - return -} - -type channelClose struct { - ReplyCode uint16 - ReplyText string - ClassId uint16 - MethodId uint16 -} - -func (msg *channelClose) id() (uint16, uint16) { - return 20, 40 -} - -func (msg *channelClose) wait() bool { - return true -} - -func (msg *channelClose) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, msg.ReplyCode); err != nil { - return - } - - if err = writeShortstr(w, msg.ReplyText); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, msg.ClassId); err != nil { - return - } - if err = binary.Write(w, binary.BigEndian, msg.MethodId); err != nil { - return - } - - return -} - -func (msg *channelClose) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &msg.ReplyCode); err != nil { - return - } - - if msg.ReplyText, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &msg.ClassId); err != nil { - return - } - if err = binary.Read(r, binary.BigEndian, &msg.MethodId); err != nil { - return - } - - return -} - -type channelCloseOk struct { -} - -func (msg *channelCloseOk) id() (uint16, uint16) { - return 20, 41 -} - -func (msg *channelCloseOk) wait() bool { - return true -} - -func (msg *channelCloseOk) write(w io.Writer) (err error) { - - return -} - -func (msg *channelCloseOk) read(r io.Reader) (err error) { - - return -} - -type exchangeDeclare struct { - reserved1 uint16 - Exchange string - Type string - Passive bool - Durable bool - AutoDelete bool - Internal bool - NoWait bool - Arguments Table -} - -func (msg *exchangeDeclare) id() (uint16, uint16) { - return 40, 10 -} - -func (msg *exchangeDeclare) wait() bool { - return true && !msg.NoWait -} - -func (msg *exchangeDeclare) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.reserved1); err != nil { - return - } - - if err = writeShortstr(w, msg.Exchange); err != nil { - return - } - if err = writeShortstr(w, msg.Type); err != nil { - return - } - - if msg.Passive { - bits |= 1 << 0 - } - - if msg.Durable { - bits |= 1 << 1 - } - - if msg.AutoDelete { - bits |= 1 << 2 - } - - if msg.Internal { - bits |= 1 << 3 - } - - if msg.NoWait { - bits |= 1 << 4 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeTable(w, msg.Arguments); err != nil { - return - } - - return -} - -func (msg *exchangeDeclare) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.reserved1); err != nil { - return - } - - if msg.Exchange, err = readShortstr(r); err != nil { - return - } - if msg.Type, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.Passive = (bits&(1<<0) > 0) - msg.Durable = (bits&(1<<1) > 0) - msg.AutoDelete = (bits&(1<<2) > 0) - msg.Internal = (bits&(1<<3) > 0) - msg.NoWait = (bits&(1<<4) > 0) - - if msg.Arguments, err = readTable(r); err != nil { - return - } - - return -} - -type exchangeDeclareOk struct { -} - -func (msg *exchangeDeclareOk) id() (uint16, uint16) { - return 40, 11 -} - -func (msg *exchangeDeclareOk) wait() bool { - return true -} - -func (msg *exchangeDeclareOk) write(w io.Writer) (err error) { - - return -} - -func (msg *exchangeDeclareOk) read(r io.Reader) (err error) { - - return -} - -type exchangeDelete struct { - reserved1 uint16 - Exchange string - IfUnused bool - NoWait bool -} - -func (msg *exchangeDelete) id() (uint16, uint16) { - return 40, 20 -} - -func (msg *exchangeDelete) wait() bool { - return true && !msg.NoWait -} - -func (msg *exchangeDelete) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.reserved1); err != nil { - return - } - - if err = writeShortstr(w, msg.Exchange); err != nil { - return - } - - if msg.IfUnused { - bits |= 1 << 0 - } - - if msg.NoWait { - bits |= 1 << 1 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *exchangeDelete) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.reserved1); err != nil { - return - } - - if msg.Exchange, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.IfUnused = (bits&(1<<0) > 0) - msg.NoWait = (bits&(1<<1) > 0) - - return -} - -type exchangeDeleteOk struct { -} - -func (msg *exchangeDeleteOk) id() (uint16, uint16) { - return 40, 21 -} - -func (msg *exchangeDeleteOk) wait() bool { - return true -} - -func (msg *exchangeDeleteOk) write(w io.Writer) (err error) { - - return -} - -func (msg *exchangeDeleteOk) read(r io.Reader) (err error) { - - return -} - -type exchangeBind struct { - reserved1 uint16 - Destination string - Source string - RoutingKey string - NoWait bool - Arguments Table -} - -func (msg *exchangeBind) id() (uint16, uint16) { - return 40, 30 -} - -func (msg *exchangeBind) wait() bool { - return true && !msg.NoWait -} - -func (msg *exchangeBind) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.reserved1); err != nil { - return - } - - if err = writeShortstr(w, msg.Destination); err != nil { - return - } - if err = writeShortstr(w, msg.Source); err != nil { - return - } - if err = writeShortstr(w, msg.RoutingKey); err != nil { - return - } - - if msg.NoWait { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeTable(w, msg.Arguments); err != nil { - return - } - - return -} - -func (msg *exchangeBind) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.reserved1); err != nil { - return - } - - if msg.Destination, err = readShortstr(r); err != nil { - return - } - if msg.Source, err = readShortstr(r); err != nil { - return - } - if msg.RoutingKey, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.NoWait = (bits&(1<<0) > 0) - - if msg.Arguments, err = readTable(r); err != nil { - return - } - - return -} - -type exchangeBindOk struct { -} - -func (msg *exchangeBindOk) id() (uint16, uint16) { - return 40, 31 -} - -func (msg *exchangeBindOk) wait() bool { - return true -} - -func (msg *exchangeBindOk) write(w io.Writer) (err error) { - - return -} - -func (msg *exchangeBindOk) read(r io.Reader) (err error) { - - return -} - -type exchangeUnbind struct { - reserved1 uint16 - Destination string - Source string - RoutingKey string - NoWait bool - Arguments Table -} - -func (msg *exchangeUnbind) id() (uint16, uint16) { - return 40, 40 -} - -func (msg *exchangeUnbind) wait() bool { - return true && !msg.NoWait -} - -func (msg *exchangeUnbind) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.reserved1); err != nil { - return - } - - if err = writeShortstr(w, msg.Destination); err != nil { - return - } - if err = writeShortstr(w, msg.Source); err != nil { - return - } - if err = writeShortstr(w, msg.RoutingKey); err != nil { - return - } - - if msg.NoWait { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeTable(w, msg.Arguments); err != nil { - return - } - - return -} - -func (msg *exchangeUnbind) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.reserved1); err != nil { - return - } - - if msg.Destination, err = readShortstr(r); err != nil { - return - } - if msg.Source, err = readShortstr(r); err != nil { - return - } - if msg.RoutingKey, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.NoWait = (bits&(1<<0) > 0) - - if msg.Arguments, err = readTable(r); err != nil { - return - } - - return -} - -type exchangeUnbindOk struct { -} - -func (msg *exchangeUnbindOk) id() (uint16, uint16) { - return 40, 51 -} - -func (msg *exchangeUnbindOk) wait() bool { - return true -} - -func (msg *exchangeUnbindOk) write(w io.Writer) (err error) { - - return -} - -func (msg *exchangeUnbindOk) read(r io.Reader) (err error) { - - return -} - -type queueDeclare struct { - reserved1 uint16 - Queue string - Passive bool - Durable bool - Exclusive bool - AutoDelete bool - NoWait bool - Arguments Table -} - -func (msg *queueDeclare) id() (uint16, uint16) { - return 50, 10 -} - -func (msg *queueDeclare) wait() bool { - return true && !msg.NoWait -} - -func (msg *queueDeclare) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.reserved1); err != nil { - return - } - - if err = writeShortstr(w, msg.Queue); err != nil { - return - } - - if msg.Passive { - bits |= 1 << 0 - } - - if msg.Durable { - bits |= 1 << 1 - } - - if msg.Exclusive { - bits |= 1 << 2 - } - - if msg.AutoDelete { - bits |= 1 << 3 - } - - if msg.NoWait { - bits |= 1 << 4 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeTable(w, msg.Arguments); err != nil { - return - } - - return -} - -func (msg *queueDeclare) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.reserved1); err != nil { - return - } - - if msg.Queue, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.Passive = (bits&(1<<0) > 0) - msg.Durable = (bits&(1<<1) > 0) - msg.Exclusive = (bits&(1<<2) > 0) - msg.AutoDelete = (bits&(1<<3) > 0) - msg.NoWait = (bits&(1<<4) > 0) - - if msg.Arguments, err = readTable(r); err != nil { - return - } - - return -} - -type queueDeclareOk struct { - Queue string - MessageCount uint32 - ConsumerCount uint32 -} - -func (msg *queueDeclareOk) id() (uint16, uint16) { - return 50, 11 -} - -func (msg *queueDeclareOk) wait() bool { - return true -} - -func (msg *queueDeclareOk) write(w io.Writer) (err error) { - - if err = writeShortstr(w, msg.Queue); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, msg.MessageCount); err != nil { - return - } - if err = binary.Write(w, binary.BigEndian, msg.ConsumerCount); err != nil { - return - } - - return -} - -func (msg *queueDeclareOk) read(r io.Reader) (err error) { - - if msg.Queue, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &msg.MessageCount); err != nil { - return - } - if err = binary.Read(r, binary.BigEndian, &msg.ConsumerCount); err != nil { - return - } - - return -} - -type queueBind struct { - reserved1 uint16 - Queue string - Exchange string - RoutingKey string - NoWait bool - Arguments Table -} - -func (msg *queueBind) id() (uint16, uint16) { - return 50, 20 -} - -func (msg *queueBind) wait() bool { - return true && !msg.NoWait -} - -func (msg *queueBind) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.reserved1); err != nil { - return - } - - if err = writeShortstr(w, msg.Queue); err != nil { - return - } - if err = writeShortstr(w, msg.Exchange); err != nil { - return - } - if err = writeShortstr(w, msg.RoutingKey); err != nil { - return - } - - if msg.NoWait { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeTable(w, msg.Arguments); err != nil { - return - } - - return -} - -func (msg *queueBind) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.reserved1); err != nil { - return - } - - if msg.Queue, err = readShortstr(r); err != nil { - return - } - if msg.Exchange, err = readShortstr(r); err != nil { - return - } - if msg.RoutingKey, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.NoWait = (bits&(1<<0) > 0) - - if msg.Arguments, err = readTable(r); err != nil { - return - } - - return -} - -type queueBindOk struct { -} - -func (msg *queueBindOk) id() (uint16, uint16) { - return 50, 21 -} - -func (msg *queueBindOk) wait() bool { - return true -} - -func (msg *queueBindOk) write(w io.Writer) (err error) { - - return -} - -func (msg *queueBindOk) read(r io.Reader) (err error) { - - return -} - -type queueUnbind struct { - reserved1 uint16 - Queue string - Exchange string - RoutingKey string - Arguments Table -} - -func (msg *queueUnbind) id() (uint16, uint16) { - return 50, 50 -} - -func (msg *queueUnbind) wait() bool { - return true -} - -func (msg *queueUnbind) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, msg.reserved1); err != nil { - return - } - - if err = writeShortstr(w, msg.Queue); err != nil { - return - } - if err = writeShortstr(w, msg.Exchange); err != nil { - return - } - if err = writeShortstr(w, msg.RoutingKey); err != nil { - return - } - - if err = writeTable(w, msg.Arguments); err != nil { - return - } - - return -} - -func (msg *queueUnbind) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &msg.reserved1); err != nil { - return - } - - if msg.Queue, err = readShortstr(r); err != nil { - return - } - if msg.Exchange, err = readShortstr(r); err != nil { - return - } - if msg.RoutingKey, err = readShortstr(r); err != nil { - return - } - - if msg.Arguments, err = readTable(r); err != nil { - return - } - - return -} - -type queueUnbindOk struct { -} - -func (msg *queueUnbindOk) id() (uint16, uint16) { - return 50, 51 -} - -func (msg *queueUnbindOk) wait() bool { - return true -} - -func (msg *queueUnbindOk) write(w io.Writer) (err error) { - - return -} - -func (msg *queueUnbindOk) read(r io.Reader) (err error) { - - return -} - -type queuePurge struct { - reserved1 uint16 - Queue string - NoWait bool -} - -func (msg *queuePurge) id() (uint16, uint16) { - return 50, 30 -} - -func (msg *queuePurge) wait() bool { - return true && !msg.NoWait -} - -func (msg *queuePurge) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.reserved1); err != nil { - return - } - - if err = writeShortstr(w, msg.Queue); err != nil { - return - } - - if msg.NoWait { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *queuePurge) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.reserved1); err != nil { - return - } - - if msg.Queue, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.NoWait = (bits&(1<<0) > 0) - - return -} - -type queuePurgeOk struct { - MessageCount uint32 -} - -func (msg *queuePurgeOk) id() (uint16, uint16) { - return 50, 31 -} - -func (msg *queuePurgeOk) wait() bool { - return true -} - -func (msg *queuePurgeOk) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, msg.MessageCount); err != nil { - return - } - - return -} - -func (msg *queuePurgeOk) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &msg.MessageCount); err != nil { - return - } - - return -} - -type queueDelete struct { - reserved1 uint16 - Queue string - IfUnused bool - IfEmpty bool - NoWait bool -} - -func (msg *queueDelete) id() (uint16, uint16) { - return 50, 40 -} - -func (msg *queueDelete) wait() bool { - return true && !msg.NoWait -} - -func (msg *queueDelete) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.reserved1); err != nil { - return - } - - if err = writeShortstr(w, msg.Queue); err != nil { - return - } - - if msg.IfUnused { - bits |= 1 << 0 - } - - if msg.IfEmpty { - bits |= 1 << 1 - } - - if msg.NoWait { - bits |= 1 << 2 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *queueDelete) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.reserved1); err != nil { - return - } - - if msg.Queue, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.IfUnused = (bits&(1<<0) > 0) - msg.IfEmpty = (bits&(1<<1) > 0) - msg.NoWait = (bits&(1<<2) > 0) - - return -} - -type queueDeleteOk struct { - MessageCount uint32 -} - -func (msg *queueDeleteOk) id() (uint16, uint16) { - return 50, 41 -} - -func (msg *queueDeleteOk) wait() bool { - return true -} - -func (msg *queueDeleteOk) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, msg.MessageCount); err != nil { - return - } - - return -} - -func (msg *queueDeleteOk) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &msg.MessageCount); err != nil { - return - } - - return -} - -type basicQos struct { - PrefetchSize uint32 - PrefetchCount uint16 - Global bool -} - -func (msg *basicQos) id() (uint16, uint16) { - return 60, 10 -} - -func (msg *basicQos) wait() bool { - return true -} - -func (msg *basicQos) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.PrefetchSize); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, msg.PrefetchCount); err != nil { - return - } - - if msg.Global { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *basicQos) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.PrefetchSize); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &msg.PrefetchCount); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.Global = (bits&(1<<0) > 0) - - return -} - -type basicQosOk struct { -} - -func (msg *basicQosOk) id() (uint16, uint16) { - return 60, 11 -} - -func (msg *basicQosOk) wait() bool { - return true -} - -func (msg *basicQosOk) write(w io.Writer) (err error) { - - return -} - -func (msg *basicQosOk) read(r io.Reader) (err error) { - - return -} - -type basicConsume struct { - reserved1 uint16 - Queue string - ConsumerTag string - NoLocal bool - NoAck bool - Exclusive bool - NoWait bool - Arguments Table -} - -func (msg *basicConsume) id() (uint16, uint16) { - return 60, 20 -} - -func (msg *basicConsume) wait() bool { - return true && !msg.NoWait -} - -func (msg *basicConsume) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.reserved1); err != nil { - return - } - - if err = writeShortstr(w, msg.Queue); err != nil { - return - } - if err = writeShortstr(w, msg.ConsumerTag); err != nil { - return - } - - if msg.NoLocal { - bits |= 1 << 0 - } - - if msg.NoAck { - bits |= 1 << 1 - } - - if msg.Exclusive { - bits |= 1 << 2 - } - - if msg.NoWait { - bits |= 1 << 3 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeTable(w, msg.Arguments); err != nil { - return - } - - return -} - -func (msg *basicConsume) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.reserved1); err != nil { - return - } - - if msg.Queue, err = readShortstr(r); err != nil { - return - } - if msg.ConsumerTag, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.NoLocal = (bits&(1<<0) > 0) - msg.NoAck = (bits&(1<<1) > 0) - msg.Exclusive = (bits&(1<<2) > 0) - msg.NoWait = (bits&(1<<3) > 0) - - if msg.Arguments, err = readTable(r); err != nil { - return - } - - return -} - -type basicConsumeOk struct { - ConsumerTag string -} - -func (msg *basicConsumeOk) id() (uint16, uint16) { - return 60, 21 -} - -func (msg *basicConsumeOk) wait() bool { - return true -} - -func (msg *basicConsumeOk) write(w io.Writer) (err error) { - - if err = writeShortstr(w, msg.ConsumerTag); err != nil { - return - } - - return -} - -func (msg *basicConsumeOk) read(r io.Reader) (err error) { - - if msg.ConsumerTag, err = readShortstr(r); err != nil { - return - } - - return -} - -type basicCancel struct { - ConsumerTag string - NoWait bool -} - -func (msg *basicCancel) id() (uint16, uint16) { - return 60, 30 -} - -func (msg *basicCancel) wait() bool { - return true && !msg.NoWait -} - -func (msg *basicCancel) write(w io.Writer) (err error) { - var bits byte - - if err = writeShortstr(w, msg.ConsumerTag); err != nil { - return - } - - if msg.NoWait { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *basicCancel) read(r io.Reader) (err error) { - var bits byte - - if msg.ConsumerTag, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.NoWait = (bits&(1<<0) > 0) - - return -} - -type basicCancelOk struct { - ConsumerTag string -} - -func (msg *basicCancelOk) id() (uint16, uint16) { - return 60, 31 -} - -func (msg *basicCancelOk) wait() bool { - return true -} - -func (msg *basicCancelOk) write(w io.Writer) (err error) { - - if err = writeShortstr(w, msg.ConsumerTag); err != nil { - return - } - - return -} - -func (msg *basicCancelOk) read(r io.Reader) (err error) { - - if msg.ConsumerTag, err = readShortstr(r); err != nil { - return - } - - return -} - -type basicPublish struct { - reserved1 uint16 - Exchange string - RoutingKey string - Mandatory bool - Immediate bool - Properties properties - Body []byte -} - -func (msg *basicPublish) id() (uint16, uint16) { - return 60, 40 -} - -func (msg *basicPublish) wait() bool { - return false -} - -func (msg *basicPublish) getContent() (properties, []byte) { - return msg.Properties, msg.Body -} - -func (msg *basicPublish) setContent(props properties, body []byte) { - msg.Properties, msg.Body = props, body -} - -func (msg *basicPublish) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.reserved1); err != nil { - return - } - - if err = writeShortstr(w, msg.Exchange); err != nil { - return - } - if err = writeShortstr(w, msg.RoutingKey); err != nil { - return - } - - if msg.Mandatory { - bits |= 1 << 0 - } - - if msg.Immediate { - bits |= 1 << 1 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *basicPublish) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.reserved1); err != nil { - return - } - - if msg.Exchange, err = readShortstr(r); err != nil { - return - } - if msg.RoutingKey, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.Mandatory = (bits&(1<<0) > 0) - msg.Immediate = (bits&(1<<1) > 0) - - return -} - -type basicReturn struct { - ReplyCode uint16 - ReplyText string - Exchange string - RoutingKey string - Properties properties - Body []byte -} - -func (msg *basicReturn) id() (uint16, uint16) { - return 60, 50 -} - -func (msg *basicReturn) wait() bool { - return false -} - -func (msg *basicReturn) getContent() (properties, []byte) { - return msg.Properties, msg.Body -} - -func (msg *basicReturn) setContent(props properties, body []byte) { - msg.Properties, msg.Body = props, body -} - -func (msg *basicReturn) write(w io.Writer) (err error) { - - if err = binary.Write(w, binary.BigEndian, msg.ReplyCode); err != nil { - return - } - - if err = writeShortstr(w, msg.ReplyText); err != nil { - return - } - if err = writeShortstr(w, msg.Exchange); err != nil { - return - } - if err = writeShortstr(w, msg.RoutingKey); err != nil { - return - } - - return -} - -func (msg *basicReturn) read(r io.Reader) (err error) { - - if err = binary.Read(r, binary.BigEndian, &msg.ReplyCode); err != nil { - return - } - - if msg.ReplyText, err = readShortstr(r); err != nil { - return - } - if msg.Exchange, err = readShortstr(r); err != nil { - return - } - if msg.RoutingKey, err = readShortstr(r); err != nil { - return - } - - return -} - -type basicDeliver struct { - ConsumerTag string - DeliveryTag uint64 - Redelivered bool - Exchange string - RoutingKey string - Properties properties - Body []byte -} - -func (msg *basicDeliver) id() (uint16, uint16) { - return 60, 60 -} - -func (msg *basicDeliver) wait() bool { - return false -} - -func (msg *basicDeliver) getContent() (properties, []byte) { - return msg.Properties, msg.Body -} - -func (msg *basicDeliver) setContent(props properties, body []byte) { - msg.Properties, msg.Body = props, body -} - -func (msg *basicDeliver) write(w io.Writer) (err error) { - var bits byte - - if err = writeShortstr(w, msg.ConsumerTag); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, msg.DeliveryTag); err != nil { - return - } - - if msg.Redelivered { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeShortstr(w, msg.Exchange); err != nil { - return - } - if err = writeShortstr(w, msg.RoutingKey); err != nil { - return - } - - return -} - -func (msg *basicDeliver) read(r io.Reader) (err error) { - var bits byte - - if msg.ConsumerTag, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &msg.DeliveryTag); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.Redelivered = (bits&(1<<0) > 0) - - if msg.Exchange, err = readShortstr(r); err != nil { - return - } - if msg.RoutingKey, err = readShortstr(r); err != nil { - return - } - - return -} - -type basicGet struct { - reserved1 uint16 - Queue string - NoAck bool -} - -func (msg *basicGet) id() (uint16, uint16) { - return 60, 70 -} - -func (msg *basicGet) wait() bool { - return true -} - -func (msg *basicGet) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.reserved1); err != nil { - return - } - - if err = writeShortstr(w, msg.Queue); err != nil { - return - } - - if msg.NoAck { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *basicGet) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.reserved1); err != nil { - return - } - - if msg.Queue, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.NoAck = (bits&(1<<0) > 0) - - return -} - -type basicGetOk struct { - DeliveryTag uint64 - Redelivered bool - Exchange string - RoutingKey string - MessageCount uint32 - Properties properties - Body []byte -} - -func (msg *basicGetOk) id() (uint16, uint16) { - return 60, 71 -} - -func (msg *basicGetOk) wait() bool { - return true -} - -func (msg *basicGetOk) getContent() (properties, []byte) { - return msg.Properties, msg.Body -} - -func (msg *basicGetOk) setContent(props properties, body []byte) { - msg.Properties, msg.Body = props, body -} - -func (msg *basicGetOk) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.DeliveryTag); err != nil { - return - } - - if msg.Redelivered { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - if err = writeShortstr(w, msg.Exchange); err != nil { - return - } - if err = writeShortstr(w, msg.RoutingKey); err != nil { - return - } - - if err = binary.Write(w, binary.BigEndian, msg.MessageCount); err != nil { - return - } - - return -} - -func (msg *basicGetOk) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.DeliveryTag); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.Redelivered = (bits&(1<<0) > 0) - - if msg.Exchange, err = readShortstr(r); err != nil { - return - } - if msg.RoutingKey, err = readShortstr(r); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &msg.MessageCount); err != nil { - return - } - - return -} - -type basicGetEmpty struct { - reserved1 string -} - -func (msg *basicGetEmpty) id() (uint16, uint16) { - return 60, 72 -} - -func (msg *basicGetEmpty) wait() bool { - return true -} - -func (msg *basicGetEmpty) write(w io.Writer) (err error) { - - if err = writeShortstr(w, msg.reserved1); err != nil { - return - } - - return -} - -func (msg *basicGetEmpty) read(r io.Reader) (err error) { - - if msg.reserved1, err = readShortstr(r); err != nil { - return - } - - return -} - -type basicAck struct { - DeliveryTag uint64 - Multiple bool -} - -func (msg *basicAck) id() (uint16, uint16) { - return 60, 80 -} - -func (msg *basicAck) wait() bool { - return false -} - -func (msg *basicAck) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.DeliveryTag); err != nil { - return - } - - if msg.Multiple { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *basicAck) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.DeliveryTag); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.Multiple = (bits&(1<<0) > 0) - - return -} - -type basicReject struct { - DeliveryTag uint64 - Requeue bool -} - -func (msg *basicReject) id() (uint16, uint16) { - return 60, 90 -} - -func (msg *basicReject) wait() bool { - return false -} - -func (msg *basicReject) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.DeliveryTag); err != nil { - return - } - - if msg.Requeue { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *basicReject) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.DeliveryTag); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.Requeue = (bits&(1<<0) > 0) - - return -} - -type basicRecoverAsync struct { - Requeue bool -} - -func (msg *basicRecoverAsync) id() (uint16, uint16) { - return 60, 100 -} - -func (msg *basicRecoverAsync) wait() bool { - return false -} - -func (msg *basicRecoverAsync) write(w io.Writer) (err error) { - var bits byte - - if msg.Requeue { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *basicRecoverAsync) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.Requeue = (bits&(1<<0) > 0) - - return -} - -type basicRecover struct { - Requeue bool -} - -func (msg *basicRecover) id() (uint16, uint16) { - return 60, 110 -} - -func (msg *basicRecover) wait() bool { - return true -} - -func (msg *basicRecover) write(w io.Writer) (err error) { - var bits byte - - if msg.Requeue { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *basicRecover) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.Requeue = (bits&(1<<0) > 0) - - return -} - -type basicRecoverOk struct { -} - -func (msg *basicRecoverOk) id() (uint16, uint16) { - return 60, 111 -} - -func (msg *basicRecoverOk) wait() bool { - return true -} - -func (msg *basicRecoverOk) write(w io.Writer) (err error) { - - return -} - -func (msg *basicRecoverOk) read(r io.Reader) (err error) { - - return -} - -type basicNack struct { - DeliveryTag uint64 - Multiple bool - Requeue bool -} - -func (msg *basicNack) id() (uint16, uint16) { - return 60, 120 -} - -func (msg *basicNack) wait() bool { - return false -} - -func (msg *basicNack) write(w io.Writer) (err error) { - var bits byte - - if err = binary.Write(w, binary.BigEndian, msg.DeliveryTag); err != nil { - return - } - - if msg.Multiple { - bits |= 1 << 0 - } - - if msg.Requeue { - bits |= 1 << 1 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *basicNack) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &msg.DeliveryTag); err != nil { - return - } - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.Multiple = (bits&(1<<0) > 0) - msg.Requeue = (bits&(1<<1) > 0) - - return -} - -type txSelect struct { -} - -func (msg *txSelect) id() (uint16, uint16) { - return 90, 10 -} - -func (msg *txSelect) wait() bool { - return true -} - -func (msg *txSelect) write(w io.Writer) (err error) { - - return -} - -func (msg *txSelect) read(r io.Reader) (err error) { - - return -} - -type txSelectOk struct { -} - -func (msg *txSelectOk) id() (uint16, uint16) { - return 90, 11 -} - -func (msg *txSelectOk) wait() bool { - return true -} - -func (msg *txSelectOk) write(w io.Writer) (err error) { - - return -} - -func (msg *txSelectOk) read(r io.Reader) (err error) { - - return -} - -type txCommit struct { -} - -func (msg *txCommit) id() (uint16, uint16) { - return 90, 20 -} - -func (msg *txCommit) wait() bool { - return true -} - -func (msg *txCommit) write(w io.Writer) (err error) { - - return -} - -func (msg *txCommit) read(r io.Reader) (err error) { - - return -} - -type txCommitOk struct { -} - -func (msg *txCommitOk) id() (uint16, uint16) { - return 90, 21 -} - -func (msg *txCommitOk) wait() bool { - return true -} - -func (msg *txCommitOk) write(w io.Writer) (err error) { - - return -} - -func (msg *txCommitOk) read(r io.Reader) (err error) { - - return -} - -type txRollback struct { -} - -func (msg *txRollback) id() (uint16, uint16) { - return 90, 30 -} - -func (msg *txRollback) wait() bool { - return true -} - -func (msg *txRollback) write(w io.Writer) (err error) { - - return -} - -func (msg *txRollback) read(r io.Reader) (err error) { - - return -} - -type txRollbackOk struct { -} - -func (msg *txRollbackOk) id() (uint16, uint16) { - return 90, 31 -} - -func (msg *txRollbackOk) wait() bool { - return true -} - -func (msg *txRollbackOk) write(w io.Writer) (err error) { - - return -} - -func (msg *txRollbackOk) read(r io.Reader) (err error) { - - return -} - -type confirmSelect struct { - Nowait bool -} - -func (msg *confirmSelect) id() (uint16, uint16) { - return 85, 10 -} - -func (msg *confirmSelect) wait() bool { - return true -} - -func (msg *confirmSelect) write(w io.Writer) (err error) { - var bits byte - - if msg.Nowait { - bits |= 1 << 0 - } - - if err = binary.Write(w, binary.BigEndian, bits); err != nil { - return - } - - return -} - -func (msg *confirmSelect) read(r io.Reader) (err error) { - var bits byte - - if err = binary.Read(r, binary.BigEndian, &bits); err != nil { - return - } - msg.Nowait = (bits&(1<<0) > 0) - - return -} - -type confirmSelectOk struct { -} - -func (msg *confirmSelectOk) id() (uint16, uint16) { - return 85, 11 -} - -func (msg *confirmSelectOk) wait() bool { - return true -} - -func (msg *confirmSelectOk) write(w io.Writer) (err error) { - - return -} - -func (msg *confirmSelectOk) read(r io.Reader) (err error) { - - return -} - -func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err error) { - mf := &methodFrame{ - ChannelId: channel, - } - - if err = binary.Read(r.r, binary.BigEndian, &mf.ClassId); err != nil { - return - } - - if err = binary.Read(r.r, binary.BigEndian, &mf.MethodId); err != nil { - return - } - - switch mf.ClassId { - - case 10: // connection - switch mf.MethodId { - - case 10: // connection start - //fmt.Println("NextMethod: class:10 method:10") - method := &connectionStart{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 11: // connection start-ok - //fmt.Println("NextMethod: class:10 method:11") - method := &connectionStartOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 20: // connection secure - //fmt.Println("NextMethod: class:10 method:20") - method := &connectionSecure{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 21: // connection secure-ok - //fmt.Println("NextMethod: class:10 method:21") - method := &connectionSecureOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 30: // connection tune - //fmt.Println("NextMethod: class:10 method:30") - method := &connectionTune{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 31: // connection tune-ok - //fmt.Println("NextMethod: class:10 method:31") - method := &connectionTuneOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 40: // connection open - //fmt.Println("NextMethod: class:10 method:40") - method := &connectionOpen{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 41: // connection open-ok - //fmt.Println("NextMethod: class:10 method:41") - method := &connectionOpenOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 50: // connection close - //fmt.Println("NextMethod: class:10 method:50") - method := &connectionClose{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 51: // connection close-ok - //fmt.Println("NextMethod: class:10 method:51") - method := &connectionCloseOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 60: // connection blocked - //fmt.Println("NextMethod: class:10 method:60") - method := &connectionBlocked{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 61: // connection unblocked - //fmt.Println("NextMethod: class:10 method:61") - method := &connectionUnblocked{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 70: // connection update-secret - //fmt.Println("NextMethod: class:10 method:70") - method := &connectionUpdateSecret{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 71: // connection update-secret-ok - //fmt.Println("NextMethod: class:10 method:71") - method := &connectionUpdateSecretOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - default: - return nil, fmt.Errorf("Bad method frame, unknown method %d for class %d", mf.MethodId, mf.ClassId) - } - - case 20: // channel - switch mf.MethodId { - - case 10: // channel open - //fmt.Println("NextMethod: class:20 method:10") - method := &channelOpen{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 11: // channel open-ok - //fmt.Println("NextMethod: class:20 method:11") - method := &channelOpenOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 20: // channel flow - //fmt.Println("NextMethod: class:20 method:20") - method := &channelFlow{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 21: // channel flow-ok - //fmt.Println("NextMethod: class:20 method:21") - method := &channelFlowOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 40: // channel close - //fmt.Println("NextMethod: class:20 method:40") - method := &channelClose{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 41: // channel close-ok - //fmt.Println("NextMethod: class:20 method:41") - method := &channelCloseOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - default: - return nil, fmt.Errorf("Bad method frame, unknown method %d for class %d", mf.MethodId, mf.ClassId) - } - - case 40: // exchange - switch mf.MethodId { - - case 10: // exchange declare - //fmt.Println("NextMethod: class:40 method:10") - method := &exchangeDeclare{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 11: // exchange declare-ok - //fmt.Println("NextMethod: class:40 method:11") - method := &exchangeDeclareOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 20: // exchange delete - //fmt.Println("NextMethod: class:40 method:20") - method := &exchangeDelete{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 21: // exchange delete-ok - //fmt.Println("NextMethod: class:40 method:21") - method := &exchangeDeleteOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 30: // exchange bind - //fmt.Println("NextMethod: class:40 method:30") - method := &exchangeBind{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 31: // exchange bind-ok - //fmt.Println("NextMethod: class:40 method:31") - method := &exchangeBindOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 40: // exchange unbind - //fmt.Println("NextMethod: class:40 method:40") - method := &exchangeUnbind{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 51: // exchange unbind-ok - //fmt.Println("NextMethod: class:40 method:51") - method := &exchangeUnbindOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - default: - return nil, fmt.Errorf("Bad method frame, unknown method %d for class %d", mf.MethodId, mf.ClassId) - } - - case 50: // queue - switch mf.MethodId { - - case 10: // queue declare - //fmt.Println("NextMethod: class:50 method:10") - method := &queueDeclare{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 11: // queue declare-ok - //fmt.Println("NextMethod: class:50 method:11") - method := &queueDeclareOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 20: // queue bind - //fmt.Println("NextMethod: class:50 method:20") - method := &queueBind{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 21: // queue bind-ok - //fmt.Println("NextMethod: class:50 method:21") - method := &queueBindOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 50: // queue unbind - //fmt.Println("NextMethod: class:50 method:50") - method := &queueUnbind{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 51: // queue unbind-ok - //fmt.Println("NextMethod: class:50 method:51") - method := &queueUnbindOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 30: // queue purge - //fmt.Println("NextMethod: class:50 method:30") - method := &queuePurge{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 31: // queue purge-ok - //fmt.Println("NextMethod: class:50 method:31") - method := &queuePurgeOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 40: // queue delete - //fmt.Println("NextMethod: class:50 method:40") - method := &queueDelete{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 41: // queue delete-ok - //fmt.Println("NextMethod: class:50 method:41") - method := &queueDeleteOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - default: - return nil, fmt.Errorf("Bad method frame, unknown method %d for class %d", mf.MethodId, mf.ClassId) - } - - case 60: // basic - switch mf.MethodId { - - case 10: // basic qos - //fmt.Println("NextMethod: class:60 method:10") - method := &basicQos{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 11: // basic qos-ok - //fmt.Println("NextMethod: class:60 method:11") - method := &basicQosOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 20: // basic consume - //fmt.Println("NextMethod: class:60 method:20") - method := &basicConsume{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 21: // basic consume-ok - //fmt.Println("NextMethod: class:60 method:21") - method := &basicConsumeOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 30: // basic cancel - //fmt.Println("NextMethod: class:60 method:30") - method := &basicCancel{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 31: // basic cancel-ok - //fmt.Println("NextMethod: class:60 method:31") - method := &basicCancelOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 40: // basic publish - //fmt.Println("NextMethod: class:60 method:40") - method := &basicPublish{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 50: // basic return - //fmt.Println("NextMethod: class:60 method:50") - method := &basicReturn{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 60: // basic deliver - //fmt.Println("NextMethod: class:60 method:60") - method := &basicDeliver{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 70: // basic get - //fmt.Println("NextMethod: class:60 method:70") - method := &basicGet{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 71: // basic get-ok - //fmt.Println("NextMethod: class:60 method:71") - method := &basicGetOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 72: // basic get-empty - //fmt.Println("NextMethod: class:60 method:72") - method := &basicGetEmpty{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 80: // basic ack - //fmt.Println("NextMethod: class:60 method:80") - method := &basicAck{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 90: // basic reject - //fmt.Println("NextMethod: class:60 method:90") - method := &basicReject{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 100: // basic recover-async - //fmt.Println("NextMethod: class:60 method:100") - method := &basicRecoverAsync{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 110: // basic recover - //fmt.Println("NextMethod: class:60 method:110") - method := &basicRecover{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 111: // basic recover-ok - //fmt.Println("NextMethod: class:60 method:111") - method := &basicRecoverOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 120: // basic nack - //fmt.Println("NextMethod: class:60 method:120") - method := &basicNack{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - default: - return nil, fmt.Errorf("Bad method frame, unknown method %d for class %d", mf.MethodId, mf.ClassId) - } - - case 90: // tx - switch mf.MethodId { - - case 10: // tx select - //fmt.Println("NextMethod: class:90 method:10") - method := &txSelect{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 11: // tx select-ok - //fmt.Println("NextMethod: class:90 method:11") - method := &txSelectOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 20: // tx commit - //fmt.Println("NextMethod: class:90 method:20") - method := &txCommit{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 21: // tx commit-ok - //fmt.Println("NextMethod: class:90 method:21") - method := &txCommitOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 30: // tx rollback - //fmt.Println("NextMethod: class:90 method:30") - method := &txRollback{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 31: // tx rollback-ok - //fmt.Println("NextMethod: class:90 method:31") - method := &txRollbackOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - default: - return nil, fmt.Errorf("Bad method frame, unknown method %d for class %d", mf.MethodId, mf.ClassId) - } - - case 85: // confirm - switch mf.MethodId { - - case 10: // confirm select - //fmt.Println("NextMethod: class:85 method:10") - method := &confirmSelect{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - case 11: // confirm select-ok - //fmt.Println("NextMethod: class:85 method:11") - method := &confirmSelectOk{} - if err = method.read(r.r); err != nil { - return - } - mf.Method = method - - default: - return nil, fmt.Errorf("Bad method frame, unknown method %d for class %d", mf.MethodId, mf.ClassId) - } - - default: - return nil, fmt.Errorf("Bad method frame, unknown class %d", mf.ClassId) - } - - return mf, nil -} diff --git a/vendor/github.com/rabbitmq/amqp091-go/types.go b/vendor/github.com/rabbitmq/amqp091-go/types.go deleted file mode 100644 index e8d8986..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/types.go +++ /dev/null @@ -1,514 +0,0 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. -// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package amqp091 - -import ( - "fmt" - "io" - "time" -) - -const DefaultExchange = "" - -// Constants for standard AMQP 0-9-1 exchange types. -const ( - ExchangeDirect = "direct" - ExchangeFanout = "fanout" - ExchangeTopic = "topic" - ExchangeHeaders = "headers" -) - -var ( - // ErrClosed is returned when the channel or connection is not open - ErrClosed = &Error{Code: ChannelError, Reason: "channel/connection is not open"} - - // ErrChannelMax is returned when Connection.Channel has been called enough - // times that all channel IDs have been exhausted in the client or the - // server. - ErrChannelMax = &Error{Code: ChannelError, Reason: "channel id space exhausted"} - - // ErrSASL is returned from Dial when the authentication mechanism could not - // be negotiated. - ErrSASL = &Error{Code: AccessRefused, Reason: "SASL could not negotiate a shared mechanism"} - - // ErrCredentials is returned when the authenticated client is not authorized - // to any vhost. - ErrCredentials = &Error{Code: AccessRefused, Reason: "username or password not allowed"} - - // ErrVhost is returned when the authenticated user is not permitted to - // access the requested Vhost. - ErrVhost = &Error{Code: AccessRefused, Reason: "no access to this vhost"} - - // ErrSyntax is hard protocol error, indicating an unsupported protocol, - // implementation or encoding. - ErrSyntax = &Error{Code: SyntaxError, Reason: "invalid field or value inside of a frame"} - - // ErrFrame is returned when the protocol frame cannot be read from the - // server, indicating an unsupported protocol or unsupported frame type. - ErrFrame = &Error{Code: FrameError, Reason: "frame could not be parsed"} - - // ErrCommandInvalid is returned when the server sends an unexpected response - // to this requested message type. This indicates a bug in this client. - ErrCommandInvalid = &Error{Code: CommandInvalid, Reason: "unexpected command received"} - - // ErrUnexpectedFrame is returned when something other than a method or - // heartbeat frame is delivered to the Connection, indicating a bug in the - // client. - ErrUnexpectedFrame = &Error{Code: UnexpectedFrame, Reason: "unexpected frame received"} - - // ErrFieldType is returned when writing a message containing a Go type unsupported by AMQP. - ErrFieldType = &Error{Code: SyntaxError, Reason: "unsupported table field type"} -) - -// internal errors used inside the library -var ( - errInvalidTypeAssertion = &Error{Code: InternalError, Reason: "type assertion unsuccessful", Server: false, Recover: true} -) - -// Error captures the code and reason a channel or connection has been closed -// by the server. -type Error struct { - Code int // constant code from the specification - Reason string // description of the error - Server bool // true when initiated from the server, false when from this library - Recover bool // true when this error can be recovered by retrying later or with different parameters -} - -func newError(code uint16, text string) *Error { - return &Error{ - Code: int(code), - Reason: text, - Recover: isSoftExceptionCode(int(code)), - Server: true, - } -} - -func (e Error) Error() string { - return fmt.Sprintf("Exception (%d) Reason: %q", e.Code, e.Reason) -} - -// Used by header frames to capture routing and header information -type properties struct { - ContentType string // MIME content type - ContentEncoding string // MIME content encoding - Headers Table // Application or header exchange table - DeliveryMode uint8 // queue implementation use - Transient (1) or Persistent (2) - Priority uint8 // queue implementation use - 0 to 9 - CorrelationId string // application use - correlation identifier - ReplyTo string // application use - address to to reply to (ex: RPC) - Expiration string // implementation use - message expiration spec - MessageId string // application use - message identifier - Timestamp time.Time // application use - message timestamp - Type string // application use - message type name - UserId string // application use - creating user id - AppId string // application use - creating application - reserved1 string // was cluster-id - process for buffer consumption -} - -// DeliveryMode. Transient means higher throughput but messages will not be -// restored on broker restart. The delivery mode of publishings is unrelated -// to the durability of the queues they reside on. Transient messages will -// not be restored to durable queues, persistent messages will be restored to -// durable queues and lost on non-durable queues during server restart. -// -// This remains typed as uint8 to match Publishing.DeliveryMode. Other -// delivery modes specific to custom queue implementations are not enumerated -// here. -const ( - Transient uint8 = 1 - Persistent uint8 = 2 -) - -// The property flags are an array of bits that indicate the presence or -// absence of each property value in sequence. The bits are ordered from most -// high to low - bit 15 indicates the first property. -const ( - flagContentType = 0x8000 - flagContentEncoding = 0x4000 - flagHeaders = 0x2000 - flagDeliveryMode = 0x1000 - flagPriority = 0x0800 - flagCorrelationId = 0x0400 - flagReplyTo = 0x0200 - flagExpiration = 0x0100 - flagMessageId = 0x0080 - flagTimestamp = 0x0040 - flagType = 0x0020 - flagUserId = 0x0010 - flagAppId = 0x0008 - flagReserved1 = 0x0004 -) - -// Queue captures the current server state of the queue on the server returned -// from Channel.QueueDeclare or Channel.QueueInspect. -type Queue struct { - Name string // server confirmed or generated name - Messages int // count of messages not awaiting acknowledgment - Consumers int // number of consumers receiving deliveries -} - -// Publishing captures the client message sent to the server. The fields -// outside of the Headers table included in this struct mirror the underlying -// fields in the content frame. They use native types for convenience and -// efficiency. -type Publishing struct { - // Application or exchange specific fields, - // the headers exchange will inspect this field. - Headers Table - - // Properties - ContentType string // MIME content type - ContentEncoding string // MIME content encoding - DeliveryMode uint8 // Transient (0 or 1) or Persistent (2) - Priority uint8 // 0 to 9 - CorrelationId string // correlation identifier - ReplyTo string // address to to reply to (ex: RPC) - Expiration string // message expiration spec - MessageId string // message identifier - Timestamp time.Time // message timestamp - Type string // message type name - UserId string // creating user id - ex: "guest" - AppId string // creating application id - - // The application specific payload of the message - Body []byte -} - -// Blocking notifies the server's TCP flow control of the Connection. When a -// server hits a memory or disk alarm it will block all connections until the -// resources are reclaimed. Use NotifyBlock on the Connection to receive these -// events. -type Blocking struct { - Active bool // TCP pushback active/inactive on server - Reason string // Server reason for activation -} - -// DeferredConfirmation represents a future publisher confirm for a message. It -// allows users to directly correlate a publishing to a confirmation. These are -// returned from PublishWithDeferredConfirm on Channels. -type DeferredConfirmation struct { - DeliveryTag uint64 - - done chan struct{} - ack bool -} - -// Confirmation notifies the acknowledgment or negative acknowledgement of a -// publishing identified by its delivery tag. Use NotifyPublish on the Channel -// to consume these events. -type Confirmation struct { - DeliveryTag uint64 // A 1 based counter of publishings from when the channel was put in Confirm mode - Ack bool // True when the server successfully received the publishing -} - -// Decimal matches the AMQP decimal type. Scale is the number of decimal -// digits Scale == 2, Value == 12345, Decimal == 123.45 -type Decimal struct { - Scale uint8 - Value int32 -} - -// Most common queue argument keys in queue declaration. For a comprehensive list -// of queue arguments, visit [RabbitMQ Queue docs]. -// -// QueueTypeArg queue argument is used to declare quorum and stream queues. -// Accepted values are QueueTypeClassic (default), QueueTypeQuorum and -// QueueTypeStream. [Quorum Queues] accept (almost) all queue arguments as their -// Classic Queues counterparts. Check [feature comparison] docs for more -// information. -// -// Queues can define their [max length] using QueueMaxLenArg and -// QueueMaxLenBytesArg queue arguments. Overflow behaviour is set using -// QueueOverflowArg. Accepted values are QueueOverflowDropHead (default), -// QueueOverflowRejectPublish and QueueOverflowRejectPublishDLX. -// -// [Queue TTL] can be defined using QueueTTLArg. That is, the time-to-live for an -// unused queue. [Queue Message TTL] can be defined using QueueMessageTTLArg. -// This will set a time-to-live for **messages** in the queue. -// -// [Stream retention] can be configured using StreamMaxLenBytesArg, to set the -// maximum size of the stream. Please note that stream queues always keep, at -// least, one segment. [Stream retention] can also be set using StreamMaxAgeArg, -// to set time-based retention. Values are string with unit suffix. Valid -// suffixes are Y, M, D, h, m, s. E.g. "7D" for one week. The maximum segment -// size can be set using StreamMaxSegmentSizeBytesArg. The default value is -// 500_000_000 bytes ~= 500 megabytes -// -// [RabbitMQ Queue docs]: https://rabbitmq.com/queues.html -// [Stream retention]: https://rabbitmq.com/streams.html#retention -// [max length]: https://rabbitmq.com/maxlength.html -// [Queue TTL]: https://rabbitmq.com/ttl.html#queue-ttl -// [Queue Message TTL]: https://rabbitmq.com/ttl.html#per-queue-message-ttl -// [Quorum Queues]: https://rabbitmq.com/quorum-queues.html -// [feature comparison]: https://rabbitmq.com/quorum-queues.html#feature-comparison -const ( - QueueTypeArg = "x-queue-type" - QueueMaxLenArg = "x-max-length" - QueueMaxLenBytesArg = "x-max-length-bytes" - StreamMaxLenBytesArg = "x-max-length-bytes" - QueueOverflowArg = "x-overflow" - QueueMessageTTLArg = "x-message-ttl" - QueueTTLArg = "x-expires" - StreamMaxAgeArg = "x-max-age" - StreamMaxSegmentSizeBytesArg = "x-stream-max-segment-size-bytes" -) - -// Values for queue arguments. Use as values for queue arguments during queue declaration. -// The following argument table will create a classic queue, with max length set to 100 messages, -// and a queue TTL of 30 minutes. -// -// args := amqp.Table{ -// amqp.QueueTypeArg: QueueTypeClassic, -// amqp.QueueMaxLenArg: 100, -// amqp.QueueTTLArg: 1800000, -// } -const ( - QueueTypeClassic = "classic" - QueueTypeQuorum = "quorum" - QueueTypeStream = "stream" - QueueOverflowDropHead = "drop-head" - QueueOverflowRejectPublish = "reject-publish" - QueueOverflowRejectPublishDLX = "reject-publish-dlx" -) - -// Table stores user supplied fields of the following types: -// -// bool -// byte -// int8 -// float32 -// float64 -// int -// int16 -// int32 -// int64 -// nil -// string -// time.Time -// amqp.Decimal -// amqp.Table -// []byte -// []interface{} - containing above types -// -// Functions taking a table will immediately fail when the table contains a -// value of an unsupported type. -// -// The caller must be specific in which precision of integer it wishes to -// encode. -// -// Use a type assertion when reading values from a table for type conversion. -// -// RabbitMQ expects int32 for integer values. -type Table map[string]interface{} - -func validateField(f interface{}) error { - switch fv := f.(type) { - case nil, bool, byte, int8, int, int16, int32, int64, float32, float64, string, []byte, Decimal, time.Time: - return nil - - case []interface{}: - for _, v := range fv { - if err := validateField(v); err != nil { - return fmt.Errorf("in array %s", err) - } - } - return nil - - case Table: - for k, v := range fv { - if err := validateField(v); err != nil { - return fmt.Errorf("table field %q %s", k, err) - } - } - return nil - } - - return fmt.Errorf("value %T not supported", f) -} - -// Validate returns and error if any Go types in the table are incompatible with AMQP types. -func (t Table) Validate() error { - return validateField(t) -} - -// Sets the connection name property. This property can be used in -// amqp.Config to set a custom connection name during amqp.DialConfig(). This -// can be helpful to identify specific connections in RabbitMQ, for debugging or -// tracing purposes. -func (t Table) SetClientConnectionName(connName string) { - t["connection_name"] = connName -} - -type message interface { - id() (uint16, uint16) - wait() bool - read(io.Reader) error - write(io.Writer) error -} - -type messageWithContent interface { - message - getContent() (properties, []byte) - setContent(properties, []byte) -} - -/* -The base interface implemented as: - -2.3.5 frame Details - -All frames consist of a header (7 octets), a payload of arbitrary size, and a 'frame-end' octet that detects -malformed frames: - - 0 1 3 7 size+7 size+8 - +------+---------+-------------+ +------------+ +-----------+ - | type | channel | size | | payload | | frame-end | - +------+---------+-------------+ +------------+ +-----------+ - octet short long size octets octet - -To read a frame, we: - - 1. Read the header and check the frame type and channel. - 2. Depending on the frame type, we read the payload and process it. - 3. Read the frame end octet. - -In realistic implementations where performance is a concern, we would use -“read-ahead buffering” or “gathering reads” to avoid doing three separate -system calls to read a frame. -*/ -type frame interface { - write(io.Writer) error - channel() uint16 -} - -/* -Perform any updates on the channel immediately after the frame is decoded while the -connection mutex is held. -*/ -func updateChannel(f frame, channel *Channel) { - if mf, isMethodFrame := f.(*methodFrame); isMethodFrame { - if _, isChannelClose := mf.Method.(*channelClose); isChannelClose { - channel.setClosed() - } - } -} - -type reader struct { - r io.Reader -} - -type writer struct { - w io.Writer -} - -// Implements the frame interface for Connection RPC -type protocolHeader struct{} - -func (protocolHeader) write(w io.Writer) error { - _, err := w.Write([]byte{'A', 'M', 'Q', 'P', 0, 0, 9, 1}) - return err -} - -func (protocolHeader) channel() uint16 { - panic("only valid as initial handshake") -} - -/* -Method frames carry the high-level protocol commands (which we call "methods"). -One method frame carries one command. The method frame payload has this format: - - 0 2 4 - +----------+-----------+-------------- - - - | class-id | method-id | arguments... - +----------+-----------+-------------- - - - short short ... - -To process a method frame, we: - 1. Read the method frame payload. - 2. Unpack it into a structure. A given method always has the same structure, - so we can unpack the method rapidly. 3. Check that the method is allowed in - the current context. - 4. Check that the method arguments are valid. - 5. Execute the method. - -Method frame bodies are constructed as a list of AMQP data fields (bits, -integers, strings and string tables). The marshalling code is trivially -generated directly from the protocol specifications, and can be very rapid. -*/ -type methodFrame struct { - ChannelId uint16 - ClassId uint16 - MethodId uint16 - Method message -} - -func (f *methodFrame) channel() uint16 { return f.ChannelId } - -/* -Heartbeating is a technique designed to undo one of TCP/IP's features, namely -its ability to recover from a broken physical connection by closing only after -a quite long time-out. In some scenarios we need to know very rapidly if a -peer is disconnected or not responding for other reasons (e.g. it is looping). -Since heartbeating can be done at a low level, we implement this as a special -type of frame that peers exchange at the transport level, rather than as a -class method. -*/ -type heartbeatFrame struct { - ChannelId uint16 -} - -func (f *heartbeatFrame) channel() uint16 { return f.ChannelId } - -/* -Certain methods (such as Basic.Publish, Basic.Deliver, etc.) are formally -defined as carrying content. When a peer sends such a method frame, it always -follows it with a content header and zero or more content body frames. - -A content header frame has this format: - - 0 2 4 12 14 - +----------+--------+-----------+----------------+------------- - - - | class-id | weight | body size | property flags | property list... - +----------+--------+-----------+----------------+------------- - - - short short long long short remainder... - -We place content body in distinct frames (rather than including it in the -method) so that AMQP may support "zero copy" techniques in which content is -never marshalled or encoded. We place the content properties in their own -frame so that recipients can selectively discard contents they do not want to -process -*/ -type headerFrame struct { - ChannelId uint16 - ClassId uint16 - weight uint16 - Size uint64 - Properties properties -} - -func (f *headerFrame) channel() uint16 { return f.ChannelId } - -/* -Content is the application data we carry from client-to-client via the AMQP -server. Content is, roughly speaking, a set of properties plus a binary data -part. The set of allowed properties are defined by the Basic class, and these -form the "content header frame". The data can be any size, and MAY be broken -into several (or many) chunks, each forming a "content body frame". - -Looking at the frames for a specific channel, as they pass on the wire, we -might see something like this: - - [method] - [method] [header] [body] [body] - [method] - ... -*/ -type bodyFrame struct { - ChannelId uint16 - Body []byte -} - -func (f *bodyFrame) channel() uint16 { return f.ChannelId } diff --git a/vendor/github.com/rabbitmq/amqp091-go/uri.go b/vendor/github.com/rabbitmq/amqp091-go/uri.go deleted file mode 100644 index 87ef09e..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/uri.go +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. -// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package amqp091 - -import ( - "errors" - "net" - "net/url" - "strconv" - "strings" -) - -var errURIScheme = errors.New("AMQP scheme must be either 'amqp://' or 'amqps://'") -var errURIWhitespace = errors.New("URI must not contain whitespace") - -var schemePorts = map[string]int{ - "amqp": 5672, - "amqps": 5671, -} - -var defaultURI = URI{ - Scheme: "amqp", - Host: "localhost", - Port: 5672, - Username: "guest", - Password: "guest", - Vhost: "/", -} - -// URI represents a parsed AMQP URI string. -type URI struct { - Scheme string - Host string - Port int - Username string - Password string - Vhost string - CertFile string // client TLS auth - path to certificate (PEM) - CACertFile string // client TLS auth - path to CA certificate (PEM) - KeyFile string // client TLS auth - path to private key (PEM) - ServerName string // client TLS auth - server name -} - -// ParseURI attempts to parse the given AMQP URI according to the spec. -// See http://www.rabbitmq.com/uri-spec.html. -// -// Default values for the fields are: -// -// Scheme: amqp -// Host: localhost -// Port: 5672 -// Username: guest -// Password: guest -// Vhost: / -// -// Supports TLS query parameters. See https://www.rabbitmq.com/uri-query-parameters.html -// -// certfile: -// keyfile: -// cacertfile: -// server_name_indication: -// -// If cacertfile is not provided, system CA certificates will be used. -// Mutual TLS (client auth) will be enabled only in case keyfile AND certfile provided. -// -// If Config.TLSClientConfig is set, TLS parameters from URI will be ignored. -func ParseURI(uri string) (URI, error) { - builder := defaultURI - - if strings.Contains(uri, " ") { - return builder, errURIWhitespace - } - - u, err := url.Parse(uri) - if err != nil { - return builder, err - } - - defaultPort, okScheme := schemePorts[u.Scheme] - - if okScheme { - builder.Scheme = u.Scheme - } else { - return builder, errURIScheme - } - - host := u.Hostname() - port := u.Port() - - if host != "" { - builder.Host = host - } - - if port != "" { - port32, err := strconv.ParseInt(port, 10, 32) - if err != nil { - return builder, err - } - builder.Port = int(port32) - } else { - builder.Port = defaultPort - } - - if u.User != nil { - builder.Username = u.User.Username() - if password, ok := u.User.Password(); ok { - builder.Password = password - } - } - - if u.Path != "" { - if strings.HasPrefix(u.Path, "/") { - if u.Host == "" && strings.HasPrefix(u.Path, "///") { - // net/url doesn't handle local context authorities and leaves that up - // to the scheme handler. In our case, we translate amqp:/// into the - // default host and whatever the vhost should be - if len(u.Path) > 3 { - builder.Vhost = u.Path[3:] - } - } else if len(u.Path) > 1 { - builder.Vhost = u.Path[1:] - } - } else { - builder.Vhost = u.Path - } - } - - // see https://www.rabbitmq.com/uri-query-parameters.html - params := u.Query() - builder.CertFile = params.Get("certfile") - builder.KeyFile = params.Get("keyfile") - builder.CACertFile = params.Get("cacertfile") - builder.ServerName = params.Get("server_name_indication") - - return builder, nil -} - -// PlainAuth returns a PlainAuth structure based on the parsed URI's -// Username and Password fields. -func (uri URI) PlainAuth() *PlainAuth { - return &PlainAuth{ - Username: uri.Username, - Password: uri.Password, - } -} - -// AMQPlainAuth returns a PlainAuth structure based on the parsed URI's -// Username and Password fields. -func (uri URI) AMQPlainAuth() *AMQPlainAuth { - return &AMQPlainAuth{ - Username: uri.Username, - Password: uri.Password, - } -} - -func (uri URI) String() string { - authority, err := url.Parse("") - if err != nil { - return err.Error() - } - - authority.Scheme = uri.Scheme - - if uri.Username != defaultURI.Username || uri.Password != defaultURI.Password { - authority.User = url.User(uri.Username) - - if uri.Password != defaultURI.Password { - authority.User = url.UserPassword(uri.Username, uri.Password) - } - } - - if defaultPort, found := schemePorts[uri.Scheme]; !found || defaultPort != uri.Port { - authority.Host = net.JoinHostPort(uri.Host, strconv.Itoa(uri.Port)) - } else { - // JoinHostPort() automatically add brackets to the host if it's - // an IPv6 address. - // - // If not port is specified, JoinHostPort() return an IP address in the - // form of "[::1]:", so we use TrimSuffix() to remove the extra ":". - authority.Host = strings.TrimSuffix(net.JoinHostPort(uri.Host, ""), ":") - } - - if uri.Vhost != defaultURI.Vhost { - // Make sure net/url does not double escape, e.g. - // "%2F" does not become "%252F". - authority.Path = uri.Vhost - authority.RawPath = url.QueryEscape(uri.Vhost) - } else { - authority.Path = "/" - } - - return authority.String() -} diff --git a/vendor/github.com/rabbitmq/amqp091-go/write.go b/vendor/github.com/rabbitmq/amqp091-go/write.go deleted file mode 100644 index d0011f8..0000000 --- a/vendor/github.com/rabbitmq/amqp091-go/write.go +++ /dev/null @@ -1,427 +0,0 @@ -// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved. -// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package amqp091 - -import ( - "bufio" - "bytes" - "encoding/binary" - "errors" - "io" - "math" - "time" -) - -func (w *writer) WriteFrameNoFlush(frame frame) (err error) { - err = frame.write(w.w) - return -} - -func (w *writer) WriteFrame(frame frame) (err error) { - if err = frame.write(w.w); err != nil { - return - } - - if buf, ok := w.w.(*bufio.Writer); ok { - err = buf.Flush() - } - - return -} - -func (f *methodFrame) write(w io.Writer) (err error) { - var payload bytes.Buffer - - if f.Method == nil { - return errors.New("malformed frame: missing method") - } - - class, method := f.Method.id() - - if err = binary.Write(&payload, binary.BigEndian, class); err != nil { - return - } - - if err = binary.Write(&payload, binary.BigEndian, method); err != nil { - return - } - - if err = f.Method.write(&payload); err != nil { - return - } - - return writeFrame(w, frameMethod, f.ChannelId, payload.Bytes()) -} - -// Heartbeat -// -// Payload is empty -func (f *heartbeatFrame) write(w io.Writer) (err error) { - return writeFrame(w, frameHeartbeat, f.ChannelId, []byte{}) -} - -// CONTENT HEADER -// 0 2 4 12 14 -// +----------+--------+-----------+----------------+------------- - - -// | class-id | weight | body size | property flags | property list... -// +----------+--------+-----------+----------------+------------- - - -// -// short short long long short remainder... -func (f *headerFrame) write(w io.Writer) (err error) { - var payload bytes.Buffer - var zeroTime time.Time - - if err = binary.Write(&payload, binary.BigEndian, f.ClassId); err != nil { - return - } - - if err = binary.Write(&payload, binary.BigEndian, f.weight); err != nil { - return - } - - if err = binary.Write(&payload, binary.BigEndian, f.Size); err != nil { - return - } - - // First pass will build the mask to be serialized, second pass will serialize - // each of the fields that appear in the mask. - - var mask uint16 - - if len(f.Properties.ContentType) > 0 { - mask = mask | flagContentType - } - if len(f.Properties.ContentEncoding) > 0 { - mask = mask | flagContentEncoding - } - if f.Properties.Headers != nil && len(f.Properties.Headers) > 0 { - mask = mask | flagHeaders - } - if f.Properties.DeliveryMode > 0 { - mask = mask | flagDeliveryMode - } - if f.Properties.Priority > 0 { - mask = mask | flagPriority - } - if len(f.Properties.CorrelationId) > 0 { - mask = mask | flagCorrelationId - } - if len(f.Properties.ReplyTo) > 0 { - mask = mask | flagReplyTo - } - if len(f.Properties.Expiration) > 0 { - mask = mask | flagExpiration - } - if len(f.Properties.MessageId) > 0 { - mask = mask | flagMessageId - } - if f.Properties.Timestamp != zeroTime { - mask = mask | flagTimestamp - } - if len(f.Properties.Type) > 0 { - mask = mask | flagType - } - if len(f.Properties.UserId) > 0 { - mask = mask | flagUserId - } - if len(f.Properties.AppId) > 0 { - mask = mask | flagAppId - } - - if err = binary.Write(&payload, binary.BigEndian, mask); err != nil { - return - } - - if hasProperty(mask, flagContentType) { - if err = writeShortstr(&payload, f.Properties.ContentType); err != nil { - return - } - } - if hasProperty(mask, flagContentEncoding) { - if err = writeShortstr(&payload, f.Properties.ContentEncoding); err != nil { - return - } - } - if hasProperty(mask, flagHeaders) { - if err = writeTable(&payload, f.Properties.Headers); err != nil { - return - } - } - if hasProperty(mask, flagDeliveryMode) { - if err = binary.Write(&payload, binary.BigEndian, f.Properties.DeliveryMode); err != nil { - return - } - } - if hasProperty(mask, flagPriority) { - if err = binary.Write(&payload, binary.BigEndian, f.Properties.Priority); err != nil { - return - } - } - if hasProperty(mask, flagCorrelationId) { - if err = writeShortstr(&payload, f.Properties.CorrelationId); err != nil { - return - } - } - if hasProperty(mask, flagReplyTo) { - if err = writeShortstr(&payload, f.Properties.ReplyTo); err != nil { - return - } - } - if hasProperty(mask, flagExpiration) { - if err = writeShortstr(&payload, f.Properties.Expiration); err != nil { - return - } - } - if hasProperty(mask, flagMessageId) { - if err = writeShortstr(&payload, f.Properties.MessageId); err != nil { - return - } - } - if hasProperty(mask, flagTimestamp) { - if err = binary.Write(&payload, binary.BigEndian, uint64(f.Properties.Timestamp.Unix())); err != nil { - return - } - } - if hasProperty(mask, flagType) { - if err = writeShortstr(&payload, f.Properties.Type); err != nil { - return - } - } - if hasProperty(mask, flagUserId) { - if err = writeShortstr(&payload, f.Properties.UserId); err != nil { - return - } - } - if hasProperty(mask, flagAppId) { - if err = writeShortstr(&payload, f.Properties.AppId); err != nil { - return - } - } - - return writeFrame(w, frameHeader, f.ChannelId, payload.Bytes()) -} - -// Body -// -// Payload is one byterange from the full body who's size is declared in the -// Header frame -func (f *bodyFrame) write(w io.Writer) (err error) { - return writeFrame(w, frameBody, f.ChannelId, f.Body) -} - -func writeFrame(w io.Writer, typ uint8, channel uint16, payload []byte) (err error) { - end := []byte{frameEnd} - size := uint(len(payload)) - - _, err = w.Write([]byte{ - typ, - byte((channel & 0xff00) >> 8), - byte((channel & 0x00ff) >> 0), - byte((size & 0xff000000) >> 24), - byte((size & 0x00ff0000) >> 16), - byte((size & 0x0000ff00) >> 8), - byte((size & 0x000000ff) >> 0), - }) - - if err != nil { - return - } - - if _, err = w.Write(payload); err != nil { - return - } - - if _, err = w.Write(end); err != nil { - return - } - - return -} - -func writeShortstr(w io.Writer, s string) (err error) { - b := []byte(s) - - var length = uint8(len(b)) - - if err = binary.Write(w, binary.BigEndian, length); err != nil { - return - } - - if _, err = w.Write(b[:length]); err != nil { - return - } - - return -} - -func writeLongstr(w io.Writer, s string) (err error) { - b := []byte(s) - - var length = uint32(len(b)) - - if err = binary.Write(w, binary.BigEndian, length); err != nil { - return - } - - if _, err = w.Write(b[:length]); err != nil { - return - } - - return -} - -/* -'A': []interface{} -'D': Decimal -'F': Table -'I': int32 -'S': string -'T': time.Time -'V': nil -'b': int8 -'B': byte -'d': float64 -'f': float32 -'l': int64 -'s': int16 -'t': bool -'x': []byte -*/ -func writeField(w io.Writer, value interface{}) (err error) { - var buf [9]byte - var enc []byte - - switch v := value.(type) { - case bool: - buf[0] = 't' - if v { - buf[1] = byte(1) - } else { - buf[1] = byte(0) - } - enc = buf[:2] - - case byte: - buf[0] = 'B' - buf[1] = v - enc = buf[:2] - - case int8: - buf[0] = 'b' - buf[1] = uint8(v) - enc = buf[:2] - - case int16: - buf[0] = 's' - binary.BigEndian.PutUint16(buf[1:3], uint16(v)) - enc = buf[:3] - - case int: - buf[0] = 'I' - binary.BigEndian.PutUint32(buf[1:5], uint32(v)) - enc = buf[:5] - - case int32: - buf[0] = 'I' - binary.BigEndian.PutUint32(buf[1:5], uint32(v)) - enc = buf[:5] - - case int64: - buf[0] = 'l' - binary.BigEndian.PutUint64(buf[1:9], uint64(v)) - enc = buf[:9] - - case float32: - buf[0] = 'f' - binary.BigEndian.PutUint32(buf[1:5], math.Float32bits(v)) - enc = buf[:5] - - case float64: - buf[0] = 'd' - binary.BigEndian.PutUint64(buf[1:9], math.Float64bits(v)) - enc = buf[:9] - - case Decimal: - buf[0] = 'D' - buf[1] = v.Scale - binary.BigEndian.PutUint32(buf[2:6], uint32(v.Value)) - enc = buf[:6] - - case string: - buf[0] = 'S' - binary.BigEndian.PutUint32(buf[1:5], uint32(len(v))) - enc = append(buf[:5], []byte(v)...) - - case []interface{}: // field-array - buf[0] = 'A' - - sec := new(bytes.Buffer) - for _, val := range v { - if err = writeField(sec, val); err != nil { - return - } - } - - binary.BigEndian.PutUint32(buf[1:5], uint32(sec.Len())) - if _, err = w.Write(buf[:5]); err != nil { - return - } - - if _, err = w.Write(sec.Bytes()); err != nil { - return - } - - return - - case time.Time: - buf[0] = 'T' - binary.BigEndian.PutUint64(buf[1:9], uint64(v.Unix())) - enc = buf[:9] - - case Table: - if _, err = w.Write([]byte{'F'}); err != nil { - return - } - return writeTable(w, v) - - case []byte: - buf[0] = 'x' - binary.BigEndian.PutUint32(buf[1:5], uint32(len(v))) - if _, err = w.Write(buf[0:5]); err != nil { - return - } - if _, err = w.Write(v); err != nil { - return - } - return - - case nil: - buf[0] = 'V' - enc = buf[:1] - - default: - return ErrFieldType - } - - _, err = w.Write(enc) - - return -} - -func writeTable(w io.Writer, table Table) (err error) { - var buf bytes.Buffer - - for key, val := range table { - if err = writeShortstr(&buf, key); err != nil { - return - } - if err = writeField(&buf, val); err != nil { - return - } - } - - return writeLongstr(w, buf.String()) -} diff --git a/vendor/modules.txt b/vendor/modules.txt deleted file mode 100644 index ca577cd..0000000 --- a/vendor/modules.txt +++ /dev/null @@ -1,3 +0,0 @@ -# github.com/rabbitmq/amqp091-go v1.8.0 -## explicit; go 1.16 -github.com/rabbitmq/amqp091-go From 8d6dbfa0bbb346e25aaa8dca7d4bce12c06dc7d8 Mon Sep 17 00:00:00 2001 From: WiRight Date: Mon, 24 Apr 2023 15:03:13 +0300 Subject: [PATCH 04/12] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=20=D0=B1=D0=B8=D0=BD=D0=B4=D0=B8=D0=BD=D0=B3?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- declare.go | 28 +++++++++++++++++---------- declate_options.go | 9 +++++++++ internal/channelmanager/safe_wraps.go | 15 ++++++++++++++ 3 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 declate_options.go diff --git a/declare.go b/declare.go index 08ff897..af46c35 100644 --- a/declare.go +++ b/declare.go @@ -2,7 +2,6 @@ package rabbitmq import ( "errors" - "fmt" "github.com/DizoftTeam/go-rabbitmq/internal/channelmanager" ) @@ -28,17 +27,23 @@ func NewDeclarator(conn *Conn) (*Declarator, error) { return result, nil } -func (d *Declarator) Declare(queue string, optionFuncs ...func(*ConsumerOptions)) error { - defaultOptions := getDefaultConsumerOptions(queue) - options := &defaultOptions - for _, optionFunc := range optionFuncs { - optionFunc(options) - } +func (d *Declarator) Close() { + d.chanManager.Close() +} - err := declareBindings(d.chanManager, *options) +func (d *Declarator) Declare(bindings []ExchangeBinding) error { + for _, binding := range bindings { + err := d.chanManager.ExchangeBindSafe( + binding.From, + binding.To, + binding.RoutingKey, + binding.NoWait, + tableToAMQPTable(binding.Args), + ) - if err != nil { - return fmt.Errorf("declare bindings failed: %w", err) + if err != nil { + return err + } } return nil @@ -115,6 +120,7 @@ func declareBindings(chanManager *channelmanager.ChannelManager, options Consume if !binding.Declare { continue } + err := chanManager.QueueBindSafe( options.QueueOptions.Name, binding.RoutingKey, @@ -122,9 +128,11 @@ func declareBindings(chanManager *channelmanager.ChannelManager, options Consume binding.NoWait, tableToAMQPTable(binding.Args), ) + if err != nil { return err } } + return nil } diff --git a/declate_options.go b/declate_options.go new file mode 100644 index 0000000..fc32518 --- /dev/null +++ b/declate_options.go @@ -0,0 +1,9 @@ +package rabbitmq + +type ExchangeBinding struct { + From string + To string + RoutingKey string + Args Table + NoWait bool +} diff --git a/internal/channelmanager/safe_wraps.go b/internal/channelmanager/safe_wraps.go index 0e96b8d..35c2557 100644 --- a/internal/channelmanager/safe_wraps.go +++ b/internal/channelmanager/safe_wraps.go @@ -105,6 +105,21 @@ func (chanManager *ChannelManager) ExchangeDeclareSafe( ) } +func (chanManager *ChannelManager) ExchangeBindSafe( + from string, key string, to string, noWait bool, args amqp.Table, +) error { + chanManager.channelMux.RLock() + defer chanManager.channelMux.RUnlock() + + return chanManager.channel.ExchangeBind( + to, + key, + from, + noWait, + args, + ) +} + // QueueBindSafe safely wraps the (*amqp.Channel).QueueBind method func (chanManager *ChannelManager) QueueBindSafe( name string, key string, exchange string, noWait bool, args amqp.Table, From fbdd93e366b0b9b70b04ebaa5abb7b978396353c Mon Sep 17 00:00:00 2001 From: WiRight Date: Mon, 24 Apr 2023 15:24:27 +0300 Subject: [PATCH 05/12] =?UTF-8?q?fix:=20=D0=94=D0=BE=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=B0=D0=BB=20=D0=B1=D0=B8=D0=BD=D0=B4=D0=B8=D0=BD?= =?UTF-8?q?=D0=B3=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- declare.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/declare.go b/declare.go index af46c35..bf6fe1a 100644 --- a/declare.go +++ b/declare.go @@ -35,8 +35,8 @@ func (d *Declarator) Declare(bindings []ExchangeBinding) error { for _, binding := range bindings { err := d.chanManager.ExchangeBindSafe( binding.From, - binding.To, binding.RoutingKey, + binding.To, binding.NoWait, tableToAMQPTable(binding.Args), ) From e9b5820b7f4fa8a1ae4671d76942e9f5cd0b8a40 Mon Sep 17 00:00:00 2001 From: WiRight Date: Tue, 25 Apr 2023 09:34:45 +0300 Subject: [PATCH 06/12] Add: DeclareExchange, DeclareQueue. Renamed BindExchanges --- declare.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/declare.go b/declare.go index bf6fe1a..422d3a6 100644 --- a/declare.go +++ b/declare.go @@ -31,7 +31,15 @@ func (d *Declarator) Close() { d.chanManager.Close() } -func (d *Declarator) Declare(bindings []ExchangeBinding) error { +func (d *Declarator) DeclareExchange(options ExchangeOptions) error { + return declareExchange(d.chanManager, options) +} + +func (d *Declarator) DeclareQueue(options QueueOptions) error { + return declareQueue(d.chanManager, options) +} + +func (d *Declarator) BindExchanges(bindings []ExchangeBinding) error { for _, binding := range bindings { err := d.chanManager.ExchangeBindSafe( binding.From, From d00549cbce899db68557d9888630a56ea0af9a1c Mon Sep 17 00:00:00 2001 From: WiRight Date: Tue, 25 Apr 2023 09:43:38 +0300 Subject: [PATCH 07/12] small fixes --- declare.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/declare.go b/declare.go index 422d3a6..24aea50 100644 --- a/declare.go +++ b/declare.go @@ -31,12 +31,24 @@ func (d *Declarator) Close() { d.chanManager.Close() } -func (d *Declarator) DeclareExchange(options ExchangeOptions) error { - return declareExchange(d.chanManager, options) +func (d *Declarator) DeclareExchange(optionFuncs ...func(*PublisherOptions)) error { + defaultOptions := getDefaultPublisherOptions() + options := &defaultOptions + for _, optionFunc := range optionFuncs { + optionFunc(options) + } + + return declareExchange(d.chanManager, options.ExchangeOptions) } -func (d *Declarator) DeclareQueue(options QueueOptions) error { - return declareQueue(d.chanManager, options) +func (d *Declarator) DeclareQueue(queue string, optionFuncs ...func(*ConsumerOptions)) error { + defaultOptions := getDefaultConsumerOptions(queue) + options := &defaultOptions + for _, optionFunc := range optionFuncs { + optionFunc(options) + } + + return declareQueue(d.chanManager, options.QueueOptions) } func (d *Declarator) BindExchanges(bindings []ExchangeBinding) error { From 327ae754194c522af89cb1d9877c609e790565fb Mon Sep 17 00:00:00 2001 From: WiRight Date: Wed, 26 Apr 2023 17:30:17 +0300 Subject: [PATCH 08/12] Fix publish to empty exchange --- publish.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/publish.go b/publish.go index bee7828..4df6c9a 100644 --- a/publish.go +++ b/publish.go @@ -165,10 +165,19 @@ func (publisher *Publisher) PublishWithContext( for _, optionFunc := range optionFuncs { optionFunc(options) } + if options.DeliveryMode == 0 { options.DeliveryMode = Transient } + if options.Exchange == "" && publisher.options.ExchangeOptions.Name != "" { + options.Exchange = publisher.options.ExchangeOptions.Name + } + + if options.Exchange == "" { + return fmt.Errorf("publishing to empty exchange") + } + for _, routingKey := range routingKeys { message := amqp.Publishing{} message.ContentType = options.ContentType From 823ce3bd16ec5f0ec62f2a1a86dec73a094bc89e Mon Sep 17 00:00:00 2001 From: WiRight Date: Wed, 26 Apr 2023 17:32:54 +0300 Subject: [PATCH 09/12] Fix publish to empty exchange v2 --- publish.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/publish.go b/publish.go index 4df6c9a..8fd0289 100644 --- a/publish.go +++ b/publish.go @@ -233,10 +233,19 @@ func (publisher *Publisher) PublishWithDeferredConfirmWithContext( for _, optionFunc := range optionFuncs { optionFunc(options) } + if options.DeliveryMode == 0 { options.DeliveryMode = Transient } + if options.Exchange == "" && publisher.options.ExchangeOptions.Name != "" { + options.Exchange = publisher.options.ExchangeOptions.Name + } + + if options.Exchange == "" { + return nil, fmt.Errorf("publishing to empty exchange") + } + var deferredConfirmations []*amqp.DeferredConfirmation for _, routingKey := range routingKeys { From dd5d807b9dca4f8d1210429b22e67624336b1d69 Mon Sep 17 00:00:00 2001 From: WiRight Date: Thu, 27 Apr 2023 13:27:07 +0300 Subject: [PATCH 10/12] Try add DispathLooseConnection --- connection.go | 34 ++++++++++++++++++- consume.go | 2 +- internal/channelmanager/channel_manager.go | 2 +- .../connectionmanager/connection_manager.go | 10 +++++- internal/dispatcher/dispatcher.go | 25 ++++++++++++-- internal/dispatcher/dispatcher_test.go | 2 +- publish.go | 2 +- 7 files changed, 69 insertions(+), 8 deletions(-) diff --git a/connection.go b/connection.go index 32a81a8..1f5e80c 100644 --- a/connection.go +++ b/connection.go @@ -1,6 +1,8 @@ package rabbitmq import ( + "sync" + "github.com/DizoftTeam/go-rabbitmq/internal/connectionmanager" amqp "github.com/rabbitmq/amqp091-go" ) @@ -12,6 +14,10 @@ type Conn struct { reconnectErrCh <-chan error closeConnectionToManagerCh chan<- struct{} + reconnectHooks []func() + looseConnectionCh <-chan error + mutex *sync.RWMutex + options ConnectionOptions } @@ -34,24 +40,50 @@ func NewConn(url string, optionFuncs ...func(*ConnectionOptions)) (*Conn, error) return nil, err } - reconnectErrCh, closeCh := manager.NotifyReconnect() + reconnectErrCh, closeCh, looseConnectionCh := manager.NotifyReconnect() + conn := &Conn{ connectionManager: manager, reconnectErrCh: reconnectErrCh, closeConnectionToManagerCh: closeCh, options: *options, + looseConnectionCh: looseConnectionCh, + + mutex: &sync.RWMutex{}, } + go conn.handleLooseConnection() go conn.handleRestarts() + return conn, nil } +func (conn *Conn) handleLooseConnection() { + for { + <-conn.looseConnectionCh + + conn.mutex.Lock() + + for _, fhook := range conn.reconnectHooks { + fhook() + } + + conn.mutex.Unlock() + } +} + func (conn *Conn) handleRestarts() { for err := range conn.reconnectErrCh { conn.options.Logger.Infof("successful connection recovery from: %v", err) } } +func (conn *Conn) RegisterReconnectHook(hook func()) { + conn.mutex.Lock() + conn.reconnectHooks = append(conn.reconnectHooks, hook) + conn.mutex.Unlock() +} + // Close closes the connection, it's not safe for re-use. // You should also close any consumers and publishers before // closing the connection diff --git a/consume.go b/consume.go index b3b682f..decfb61 100644 --- a/consume.go +++ b/consume.go @@ -67,7 +67,7 @@ func NewConsumer( if err != nil { return nil, err } - reconnectErrCh, closeCh := chanManager.NotifyReconnect() + reconnectErrCh, closeCh, _ := chanManager.NotifyReconnect() consumer := &Consumer{ chanManager: chanManager, diff --git a/internal/channelmanager/channel_manager.go b/internal/channelmanager/channel_manager.go index 81a9759..b6e7f18 100644 --- a/internal/channelmanager/channel_manager.go +++ b/internal/channelmanager/channel_manager.go @@ -144,6 +144,6 @@ func (chanManager *ChannelManager) Close() error { // NotifyReconnect adds a new subscriber that will receive error messages whenever // the connection manager has successfully reconnect to the server -func (chanManager *ChannelManager) NotifyReconnect() (<-chan error, chan<- struct{}) { +func (chanManager *ChannelManager) NotifyReconnect() (<-chan error, chan<- struct{}, <-chan error) { return chanManager.dispatcher.AddSubscriber() } diff --git a/internal/connectionmanager/connection_manager.go b/internal/connectionmanager/connection_manager.go index bfbd513..291ad2f 100644 --- a/internal/connectionmanager/connection_manager.go +++ b/internal/connectionmanager/connection_manager.go @@ -58,7 +58,7 @@ func (connManager *ConnectionManager) Close() error { // NotifyReconnect adds a new subscriber that will receive error messages whenever // the connection manager has successfully reconnected to the server -func (connManager *ConnectionManager) NotifyReconnect() (<-chan error, chan<- struct{}) { +func (connManager *ConnectionManager) NotifyReconnect() (<-chan error, chan<- struct{}, <-chan error) { return connManager.dispatcher.AddSubscriber() } @@ -81,12 +81,15 @@ func (connManager *ConnectionManager) startNotifyClose() { notifyCloseChan := connManager.connection.NotifyClose(make(chan *amqp.Error, 1)) err := <-notifyCloseChan + if err != nil { connManager.logger.Errorf("attempting to reconnect to amqp server after connection close with error: %v", err) + connManager.dispatcher.DispathLooseConnection(err) connManager.reconnectLoop() connManager.logger.Warnf("successfully reconnected to amqp server") connManager.dispatcher.Dispatch(err) } + if err == nil { connManager.logger.Infof("amqp connection closed gracefully") } @@ -111,11 +114,14 @@ func (connManager *ConnectionManager) reconnectLoop() { connManager.logger.Infof("waiting %s seconds to attempt to reconnect to amqp server", connManager.ReconnectInterval) time.Sleep(connManager.ReconnectInterval) err := connManager.reconnect() + if err != nil { connManager.logger.Errorf("error reconnecting to amqp server: %v", err) } else { connManager.incrementReconnectionCount() + go connManager.startNotifyClose() + return } } @@ -126,6 +132,7 @@ func (connManager *ConnectionManager) reconnect() error { connManager.connectionMux.Lock() defer connManager.connectionMux.Unlock() newConn, err := amqp.DialConfig(connManager.url, amqp.Config(connManager.amqpConfig)) + if err != nil { return err } @@ -135,5 +142,6 @@ func (connManager *ConnectionManager) reconnect() error { } connManager.connection = newConn + return nil } diff --git a/internal/dispatcher/dispatcher.go b/internal/dispatcher/dispatcher.go index 52385c6..c57ee51 100644 --- a/internal/dispatcher/dispatcher.go +++ b/internal/dispatcher/dispatcher.go @@ -15,6 +15,7 @@ type Dispatcher struct { } type dispatchSubscriber struct { + notifyClosedChan chan error notifyCancelOrCloseChan chan error closeCh <-chan struct{} } @@ -31,30 +32,49 @@ func NewDispatcher() *Dispatcher { func (d *Dispatcher) Dispatch(err error) error { d.subscribersMux.Lock() defer d.subscribersMux.Unlock() + for _, subscriber := range d.subscribers { select { case <-time.After(time.Second * 5): log.Println("Unexpected rabbitmq error: timeout in dispatch") + case subscriber.notifyCancelOrCloseChan <- err: } } + + return nil +} + +// DispathLooseConnection dispatching that connection to RabbitMQ is loosed +func (d *Dispatcher) DispathLooseConnection(err error) error { + d.subscribersMux.Lock() + defer d.subscribersMux.Unlock() + + for _, subscriber := range d.subscribers { + subscriber.notifyClosedChan <- err + } + return nil } // AddSubscriber - -func (d *Dispatcher) AddSubscriber() (<-chan error, chan<- struct{}) { +func (d *Dispatcher) AddSubscriber() (<-chan error, chan<- struct{}, <-chan error) { const maxRand = math.MaxInt const minRand = 0 id := rand.Intn(maxRand-minRand) + minRand closeCh := make(chan struct{}) notifyCancelOrCloseChan := make(chan error) + notifyClosedChan := make(chan error) d.subscribersMux.Lock() + d.subscribers[id] = dispatchSubscriber{ + notifyClosedChan: notifyClosedChan, notifyCancelOrCloseChan: notifyCancelOrCloseChan, closeCh: closeCh, } + d.subscribersMux.Unlock() go func(id int) { @@ -68,5 +88,6 @@ func (d *Dispatcher) AddSubscriber() (<-chan error, chan<- struct{}) { close(sub.notifyCancelOrCloseChan) delete(d.subscribers, id) }(id) - return notifyCancelOrCloseChan, closeCh + + return notifyCancelOrCloseChan, closeCh, notifyClosedChan } diff --git a/internal/dispatcher/dispatcher_test.go b/internal/dispatcher/dispatcher_test.go index afc5509..b79e48c 100644 --- a/internal/dispatcher/dispatcher_test.go +++ b/internal/dispatcher/dispatcher_test.go @@ -25,7 +25,7 @@ func TestAddSubscriber(t *testing.T) { func TestCloseSubscriber(t *testing.T) { d := NewDispatcher() - _, closeCh := d.AddSubscriber() + _, closeCh, _ := d.AddSubscriber() close(closeCh) time.Sleep(time.Millisecond) if len(d.subscribers) != 0 { diff --git a/publish.go b/publish.go index 8fd0289..7f292c6 100644 --- a/publish.go +++ b/publish.go @@ -83,7 +83,7 @@ func NewPublisher(conn *Conn, optionFuncs ...func(*PublisherOptions)) (*Publishe return nil, err } - reconnectErrCh, closeCh := chanManager.NotifyReconnect() + reconnectErrCh, closeCh, _ := chanManager.NotifyReconnect() publisher := &Publisher{ chanManager: chanManager, connManager: conn.connectionManager, From 89c5b17a14eb8e46a99fd60fff63d06991a0cdb0 Mon Sep 17 00:00:00 2001 From: WiRight Date: Thu, 27 Apr 2023 13:38:51 +0300 Subject: [PATCH 11/12] Try add DispathLooseConnection v2 --- connection.go | 10 ++++------ internal/channelmanager/channel_manager.go | 4 ++++ internal/connectionmanager/connection_manager.go | 1 + 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/connection.go b/connection.go index 1f5e80c..727f86c 100644 --- a/connection.go +++ b/connection.go @@ -14,7 +14,7 @@ type Conn struct { reconnectErrCh <-chan error closeConnectionToManagerCh chan<- struct{} - reconnectHooks []func() + reconnectHooks []func(error) looseConnectionCh <-chan error mutex *sync.RWMutex @@ -59,13 +59,11 @@ func NewConn(url string, optionFuncs ...func(*ConnectionOptions)) (*Conn, error) } func (conn *Conn) handleLooseConnection() { - for { - <-conn.looseConnectionCh - + for err := range conn.looseConnectionCh { conn.mutex.Lock() for _, fhook := range conn.reconnectHooks { - fhook() + fhook(err) } conn.mutex.Unlock() @@ -78,7 +76,7 @@ func (conn *Conn) handleRestarts() { } } -func (conn *Conn) RegisterReconnectHook(hook func()) { +func (conn *Conn) RegisterReconnectHook(hook func(error)) { conn.mutex.Lock() conn.reconnectHooks = append(conn.reconnectHooks, hook) conn.mutex.Unlock() diff --git a/internal/channelmanager/channel_manager.go b/internal/channelmanager/channel_manager.go index b6e7f18..457750b 100644 --- a/internal/channelmanager/channel_manager.go +++ b/internal/channelmanager/channel_manager.go @@ -40,7 +40,9 @@ func NewChannelManager(connManager *connectionmanager.ConnectionManager, log log reconnectionCountMux: &sync.Mutex{}, dispatcher: dispatcher.NewDispatcher(), } + go chanManager.startNotifyCancelOrClosed() + return &chanManager, nil } @@ -52,6 +54,7 @@ func getNewChannel(connManager *connectionmanager.ConnectionManager) (*amqp.Chan if err != nil { return nil, err } + return ch, nil } @@ -71,6 +74,7 @@ func (chanManager *ChannelManager) startNotifyCancelOrClosed() { chanManager.logger.Warnf("successfully reconnected to amqp server") chanManager.dispatcher.Dispatch(err) } + if err == nil { chanManager.logger.Infof("amqp channel closed gracefully") } diff --git a/internal/connectionmanager/connection_manager.go b/internal/connectionmanager/connection_manager.go index 291ad2f..5d107eb 100644 --- a/internal/connectionmanager/connection_manager.go +++ b/internal/connectionmanager/connection_manager.go @@ -88,6 +88,7 @@ func (connManager *ConnectionManager) startNotifyClose() { connManager.reconnectLoop() connManager.logger.Warnf("successfully reconnected to amqp server") connManager.dispatcher.Dispatch(err) + connManager.dispatcher.DispathLooseConnection(nil) } if err == nil { From 56e0b50b2b204c5d88c00e00d975a0c63f6b5418 Mon Sep 17 00:00:00 2001 From: WiRight Date: Wed, 14 Jun 2023 15:01:48 +0300 Subject: [PATCH 12/12] try fix goroutines leak --- consume.go | 36 ++++++++++++------- go.mod | 5 ++- go.sum | 2 ++ internal/channelmanager/channel_manager.go | 20 +++++++---- .../connectionmanager/connection_manager.go | 23 +++++++----- internal/dispatcher/dispatcher.go | 8 +++-- 6 files changed, 64 insertions(+), 30 deletions(-) diff --git a/consume.go b/consume.go index decfb61..e46a914 100644 --- a/consume.go +++ b/consume.go @@ -31,6 +31,7 @@ type Consumer struct { chanManager *channelmanager.ChannelManager reconnectErrCh <-chan error closeConnectionToManagerCh chan<- struct{} + notifyClosedChan <-chan error options ConsumerOptions isClosedMux *sync.RWMutex @@ -67,12 +68,13 @@ func NewConsumer( if err != nil { return nil, err } - reconnectErrCh, closeCh, _ := chanManager.NotifyReconnect() + reconnectErrCh, closeCh, notifyClosedChan := chanManager.NotifyReconnect() consumer := &Consumer{ chanManager: chanManager, reconnectErrCh: reconnectErrCh, closeConnectionToManagerCh: closeCh, + notifyClosedChan: notifyClosedChan, options: *options, isClosedMux: &sync.RWMutex{}, isClosed: false, @@ -82,6 +84,7 @@ func NewConsumer( handler, *options, ) + if err != nil { return nil, err } @@ -89,13 +92,16 @@ func NewConsumer( go func() { for err := range consumer.reconnectErrCh { consumer.options.Logger.Infof("successful consumer recovery from: %v", err) + err = consumer.startGoroutines( handler, *options, ) + if err != nil { consumer.options.Logger.Fatalf("error restarting consumer goroutines after cancel or close: %v", err) consumer.options.Logger.Fatalf("consumer closing, unable to recover") + return } } @@ -111,18 +117,18 @@ func NewConsumer( func (consumer *Consumer) Close() { consumer.isClosedMux.Lock() defer consumer.isClosedMux.Unlock() + consumer.isClosed = true + // close the channel so that rabbitmq server knows that the // consumer has been stopped. - err := consumer.chanManager.Close() - if err != nil { + if err := consumer.chanManager.Close(); err != nil { consumer.options.Logger.Warnf("error while closing the channel: %v", err) } consumer.options.Logger.Infof("closing consumer...") - go func() { - consumer.closeConnectionToManagerCh <- struct{}{} - }() + + close(consumer.closeConnectionToManagerCh) } // startGoroutines declares the queue if it doesn't exist, @@ -137,19 +143,20 @@ func (consumer *Consumer) startGoroutines( 0, options.QOSGlobal, ) + if err != nil { return fmt.Errorf("declare qos failed: %w", err) } - err = declareExchange(consumer.chanManager, options.ExchangeOptions) - if err != nil { + + if err = declareExchange(consumer.chanManager, options.ExchangeOptions); err != nil { return fmt.Errorf("declare exchange failed: %w", err) } - err = declareQueue(consumer.chanManager, options.QueueOptions) - if err != nil { + + if err = declareQueue(consumer.chanManager, options.QueueOptions); err != nil { return fmt.Errorf("declare queue failed: %w", err) } - err = declareBindings(consumer.chanManager, options) - if err != nil { + + if err = declareBindings(consumer.chanManager, options); err != nil { return fmt.Errorf("declare bindings failed: %w", err) } @@ -162,6 +169,7 @@ func (consumer *Consumer) startGoroutines( options.RabbitConsumerOptions.NoWait, tableToAMQPTable(options.RabbitConsumerOptions.Args), ) + if err != nil { return err } @@ -169,13 +177,16 @@ func (consumer *Consumer) startGoroutines( for i := 0; i < options.Concurrency; i++ { go handlerGoroutine(consumer, msgs, options, handler) } + consumer.options.Logger.Infof("Processing messages on %v goroutines", options.Concurrency) + return nil } func (consumer *Consumer) getIsClosed() bool { consumer.isClosedMux.RLock() defer consumer.isClosedMux.RUnlock() + return consumer.isClosed } @@ -208,5 +219,6 @@ func handlerGoroutine(consumer *Consumer, msgs <-chan amqp.Delivery, consumeOpti } } } + consumer.options.Logger.Infof("rabbit consumer goroutine closed") } diff --git a/go.mod b/go.mod index 3aba60f..bb9de09 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module github.com/DizoftTeam/go-rabbitmq go 1.20 -require github.com/rabbitmq/amqp091-go v1.8.0 +require ( + github.com/rabbitmq/amqp091-go v1.8.0 + github.com/wagslane/go-rabbitmq v0.12.3 +) diff --git a/go.sum b/go.sum index 787640a..98d70f1 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/wagslane/go-rabbitmq v0.12.3 h1:nHoW6SgwaGNTjNyHGhcZwdJGru2228RZTwucxqmgA9M= +github.com/wagslane/go-rabbitmq v0.12.3/go.mod h1:1sUJ53rrW2AIA7LEp8ymmmebHqqq8ksH/gXIfUP0I0s= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/channelmanager/channel_manager.go b/internal/channelmanager/channel_manager.go index 457750b..a5c3c48 100644 --- a/internal/channelmanager/channel_manager.go +++ b/internal/channelmanager/channel_manager.go @@ -73,6 +73,7 @@ func (chanManager *ChannelManager) startNotifyCancelOrClosed() { chanManager.reconnectLoop() chanManager.logger.Warnf("successfully reconnected to amqp server") chanManager.dispatcher.Dispatch(err) + chanManager.dispatcher.DispatchLooseConnection(err) } if err == nil { @@ -83,6 +84,7 @@ func (chanManager *ChannelManager) startNotifyCancelOrClosed() { chanManager.reconnectLoop() chanManager.logger.Warnf("successfully reconnected to amqp server after cancel") chanManager.dispatcher.Dispatch(errors.New(err)) + chanManager.dispatcher.DispatchLooseConnection(errors.New(err)) } } @@ -90,12 +92,14 @@ func (chanManager *ChannelManager) startNotifyCancelOrClosed() { func (chanManager *ChannelManager) GetReconnectionCount() uint { chanManager.reconnectionCountMux.Lock() defer chanManager.reconnectionCountMux.Unlock() + return chanManager.reconnectionCount } func (chanManager *ChannelManager) incrementReconnectionCount() { chanManager.reconnectionCountMux.Lock() defer chanManager.reconnectionCountMux.Unlock() + chanManager.reconnectionCount++ } @@ -103,13 +107,18 @@ func (chanManager *ChannelManager) incrementReconnectionCount() { func (chanManager *ChannelManager) reconnectLoop() { for { chanManager.logger.Infof("waiting %s seconds to attempt to reconnect to amqp server", chanManager.reconnectInterval) + time.Sleep(chanManager.reconnectInterval) + err := chanManager.reconnect() + if err != nil { chanManager.logger.Errorf("error reconnecting to amqp server: %v", err) } else { chanManager.incrementReconnectionCount() + go chanManager.startNotifyCancelOrClosed() + return } } @@ -119,7 +128,9 @@ func (chanManager *ChannelManager) reconnectLoop() { func (chanManager *ChannelManager) reconnect() error { chanManager.channelMux.Lock() defer chanManager.channelMux.Unlock() + newChannel, err := getNewChannel(chanManager.connManager) + if err != nil { return err } @@ -129,21 +140,18 @@ func (chanManager *ChannelManager) reconnect() error { } chanManager.channel = newChannel + return nil } // Close safely closes the current channel and connection func (chanManager *ChannelManager) Close() error { chanManager.logger.Infof("closing channel manager...") + chanManager.channelMux.Lock() defer chanManager.channelMux.Unlock() - err := chanManager.channel.Close() - if err != nil { - return err - } - - return nil + return chanManager.channel.Close() } // NotifyReconnect adds a new subscriber that will receive error messages whenever diff --git a/internal/connectionmanager/connection_manager.go b/internal/connectionmanager/connection_manager.go index 5d107eb..df31de1 100644 --- a/internal/connectionmanager/connection_manager.go +++ b/internal/connectionmanager/connection_manager.go @@ -24,10 +24,11 @@ type ConnectionManager struct { // NewConnectionManager creates a new connection manager func NewConnectionManager(url string, conf amqp.Config, log logger.Logger, reconnectInterval time.Duration) (*ConnectionManager, error) { - conn, err := amqp.DialConfig(url, amqp.Config(conf)) + conn, err := amqp.DialConfig(url, conf) if err != nil { return nil, err } + connManager := ConnectionManager{ logger: log, url: url, @@ -39,21 +40,20 @@ func NewConnectionManager(url string, conf amqp.Config, log logger.Logger, recon reconnectionCountMux: &sync.Mutex{}, dispatcher: dispatcher.NewDispatcher(), } + go connManager.startNotifyClose() + return &connManager, nil } // Close safely closes the current channel and connection func (connManager *ConnectionManager) Close() error { connManager.logger.Infof("closing connection manager...") + connManager.connectionMux.Lock() defer connManager.connectionMux.Unlock() - err := connManager.connection.Close() - if err != nil { - return err - } - return nil + return connManager.connection.Close() } // NotifyReconnect adds a new subscriber that will receive error messages whenever @@ -84,11 +84,11 @@ func (connManager *ConnectionManager) startNotifyClose() { if err != nil { connManager.logger.Errorf("attempting to reconnect to amqp server after connection close with error: %v", err) - connManager.dispatcher.DispathLooseConnection(err) + connManager.dispatcher.DispatchLooseConnection(err) connManager.reconnectLoop() connManager.logger.Warnf("successfully reconnected to amqp server") connManager.dispatcher.Dispatch(err) - connManager.dispatcher.DispathLooseConnection(nil) + connManager.dispatcher.DispatchLooseConnection(nil) } if err == nil { @@ -100,12 +100,14 @@ func (connManager *ConnectionManager) startNotifyClose() { func (connManager *ConnectionManager) GetReconnectionCount() uint { connManager.reconnectionCountMux.Lock() defer connManager.reconnectionCountMux.Unlock() + return connManager.reconnectionCount } func (connManager *ConnectionManager) incrementReconnectionCount() { connManager.reconnectionCountMux.Lock() defer connManager.reconnectionCountMux.Unlock() + connManager.reconnectionCount++ } @@ -113,7 +115,9 @@ func (connManager *ConnectionManager) incrementReconnectionCount() { func (connManager *ConnectionManager) reconnectLoop() { for { connManager.logger.Infof("waiting %s seconds to attempt to reconnect to amqp server", connManager.ReconnectInterval) + time.Sleep(connManager.ReconnectInterval) + err := connManager.reconnect() if err != nil { @@ -132,7 +136,8 @@ func (connManager *ConnectionManager) reconnectLoop() { func (connManager *ConnectionManager) reconnect() error { connManager.connectionMux.Lock() defer connManager.connectionMux.Unlock() - newConn, err := amqp.DialConfig(connManager.url, amqp.Config(connManager.amqpConfig)) + + newConn, err := amqp.DialConfig(connManager.url, connManager.amqpConfig) if err != nil { return err diff --git a/internal/dispatcher/dispatcher.go b/internal/dispatcher/dispatcher.go index c57ee51..39beadf 100644 --- a/internal/dispatcher/dispatcher.go +++ b/internal/dispatcher/dispatcher.go @@ -45,8 +45,8 @@ func (d *Dispatcher) Dispatch(err error) error { return nil } -// DispathLooseConnection dispatching that connection to RabbitMQ is loosed -func (d *Dispatcher) DispathLooseConnection(err error) error { +// DispatchLooseConnection dispatching that connection to RabbitMQ is loosed +func (d *Dispatcher) DispatchLooseConnection(err error) error { d.subscribersMux.Lock() defer d.subscribersMux.Unlock() @@ -79,12 +79,16 @@ func (d *Dispatcher) AddSubscriber() (<-chan error, chan<- struct{}, <-chan erro go func(id int) { <-closeCh + d.subscribersMux.Lock() defer d.subscribersMux.Unlock() + sub, ok := d.subscribers[id] + if !ok { return } + close(sub.notifyCancelOrCloseChan) delete(d.subscribers, id) }(id)