From 12610c46bced9c6fd043d7fbe50e8a16c7a86e16 Mon Sep 17 00:00:00 2001 From: CrazyMax <1951866+crazy-max@users.noreply.github.com> Date: Sun, 15 Dec 2024 00:43:49 +0100 Subject: [PATCH] switch to github.com/rabbitmq/amqp091-go module --- go.mod | 2 +- go.sum | 6 +- internal/notif/amqp/client.go | 2 +- .../github.com/rabbitmq/amqp091-go/.gitignore | 6 + .../rabbitmq/amqp091-go/.golangci.yml | 3 + .../rabbitmq/amqp091-go/CHANGELOG.md | 363 +++++++++++++ .../rabbitmq/amqp091-go/CODE_OF_CONDUCT.md | 77 +++ .../rabbitmq/amqp091-go/CONTRIBUTING.md | 62 +++ .../amqp => rabbitmq/amqp091-go}/LICENSE | 6 +- .../github.com/rabbitmq/amqp091-go/Makefile | 57 +++ .../github.com/rabbitmq/amqp091-go/README.md | 105 ++++ .../github.com/rabbitmq/amqp091-go/RELEASE.md | 16 + .../amqp => rabbitmq/amqp091-go}/allocator.go | 47 +- .../amqp => rabbitmq/amqp091-go}/auth.go | 31 +- .../amqp => rabbitmq/amqp091-go}/certs.sh | 12 +- .../rabbitmq/amqp091-go/change_version.sh | 4 + .../amqp => rabbitmq/amqp091-go}/channel.go | 447 ++++++++++++---- .../rabbitmq/amqp091-go/confirms.go | 238 +++++++++ .../amqp091-go}/connection.go | 482 +++++++++++++++--- .../amqp => rabbitmq/amqp091-go}/consumers.go | 33 +- .../amqp => rabbitmq/amqp091-go}/delivery.go | 8 +- vendor/github.com/rabbitmq/amqp091-go/doc.go | 160 ++++++ vendor/github.com/rabbitmq/amqp091-go/fuzz.go | 23 + vendor/github.com/rabbitmq/amqp091-go/gen.ps1 | 14 + .../amqp => rabbitmq/amqp091-go}/gen.sh | 0 vendor/github.com/rabbitmq/amqp091-go/log.go | 23 + .../amqp => rabbitmq/amqp091-go}/read.go | 76 ++- .../amqp => rabbitmq/amqp091-go}/return.go | 6 +- .../amqp => rabbitmq/amqp091-go}/spec091.go | 206 +++++--- .../amqp => rabbitmq/amqp091-go}/types.go | 272 +++++++--- .../amqp => rabbitmq/amqp091-go}/uri.go | 114 ++++- .../amqp => rabbitmq/amqp091-go}/write.go | 32 +- vendor/github.com/streadway/amqp/.gitignore | 12 - vendor/github.com/streadway/amqp/.travis.yml | 25 - .../github.com/streadway/amqp/CONTRIBUTING.md | 35 -- vendor/github.com/streadway/amqp/README.md | 100 ---- vendor/github.com/streadway/amqp/confirms.go | 94 ---- vendor/github.com/streadway/amqp/doc.go | 108 ---- vendor/github.com/streadway/amqp/fuzz.go | 17 - vendor/github.com/streadway/amqp/pre-commit | 67 --- vendor/modules.txt | 6 +- 41 files changed, 2504 insertions(+), 893 deletions(-) create mode 100644 vendor/github.com/rabbitmq/amqp091-go/.gitignore create mode 100644 vendor/github.com/rabbitmq/amqp091-go/.golangci.yml create mode 100644 vendor/github.com/rabbitmq/amqp091-go/CHANGELOG.md create mode 100644 vendor/github.com/rabbitmq/amqp091-go/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/rabbitmq/amqp091-go/CONTRIBUTING.md rename vendor/github.com/{streadway/amqp => rabbitmq/amqp091-go}/LICENSE (89%) create mode 100644 vendor/github.com/rabbitmq/amqp091-go/Makefile create mode 100644 vendor/github.com/rabbitmq/amqp091-go/README.md create mode 100644 vendor/github.com/rabbitmq/amqp091-go/RELEASE.md rename vendor/github.com/{streadway/amqp => rabbitmq/amqp091-go}/allocator.go (71%) rename vendor/github.com/{streadway/amqp => rabbitmq/amqp091-go}/auth.go (63%) rename vendor/github.com/{streadway/amqp => rabbitmq/amqp091-go}/certs.sh (93%) create mode 100644 vendor/github.com/rabbitmq/amqp091-go/change_version.sh rename vendor/github.com/{streadway/amqp => rabbitmq/amqp091-go}/channel.go (77%) create mode 100644 vendor/github.com/rabbitmq/amqp091-go/confirms.go rename vendor/github.com/{streadway/amqp => rabbitmq/amqp091-go}/connection.go (62%) rename vendor/github.com/{streadway/amqp => rabbitmq/amqp091-go}/consumers.go (65%) rename vendor/github.com/{streadway/amqp => rabbitmq/amqp091-go}/delivery.go (96%) create mode 100644 vendor/github.com/rabbitmq/amqp091-go/doc.go create mode 100644 vendor/github.com/rabbitmq/amqp091-go/fuzz.go create mode 100644 vendor/github.com/rabbitmq/amqp091-go/gen.ps1 rename vendor/github.com/{streadway/amqp => rabbitmq/amqp091-go}/gen.sh (100%) create mode 100644 vendor/github.com/rabbitmq/amqp091-go/log.go rename vendor/github.com/{streadway/amqp => rabbitmq/amqp091-go}/read.go (83%) rename vendor/github.com/{streadway/amqp => rabbitmq/amqp091-go}/return.go (93%) rename vendor/github.com/{streadway/amqp => rabbitmq/amqp091-go}/spec091.go (92%) rename vendor/github.com/{streadway/amqp => rabbitmq/amqp091-go}/types.go (57%) rename vendor/github.com/{streadway/amqp => rabbitmq/amqp091-go}/uri.go (52%) rename vendor/github.com/{streadway/amqp => rabbitmq/amqp091-go}/write.go (94%) delete mode 100644 vendor/github.com/streadway/amqp/.gitignore delete mode 100644 vendor/github.com/streadway/amqp/.travis.yml delete mode 100644 vendor/github.com/streadway/amqp/CONTRIBUTING.md delete mode 100644 vendor/github.com/streadway/amqp/README.md delete mode 100644 vendor/github.com/streadway/amqp/confirms.go delete mode 100644 vendor/github.com/streadway/amqp/doc.go delete mode 100644 vendor/github.com/streadway/amqp/fuzz.go delete mode 100644 vendor/github.com/streadway/amqp/pre-commit diff --git a/go.mod b/go.mod index 98f5b87ff..005b4e0c1 100644 --- a/go.mod +++ b/go.mod @@ -34,10 +34,10 @@ require ( github.com/panjf2000/ants/v2 v2.10.0 github.com/pkg/errors v0.9.1 github.com/pkg/profile v1.7.0 + github.com/rabbitmq/amqp091-go v1.10.0 github.com/rs/zerolog v1.33.0 github.com/russross/blackfriday/v2 v2.1.0 github.com/sirupsen/logrus v1.9.3 - github.com/streadway/amqp v1.1.0 github.com/stretchr/testify v1.9.0 github.com/tidwall/pretty v1.2.1 go.etcd.io/bbolt v1.3.10 diff --git a/go.sum b/go.sum index d447a022a..7f6923a19 100644 --- a/go.sum +++ b/go.sum @@ -281,6 +281,8 @@ github.com/prometheus/common v0.51.1 h1:eIjN50Bwglz6a/c3hAgSMcofL3nD+nFQkV6Dd4Ds github.com/prometheus/common v0.51.1/go.mod h1:lrWtQx+iDfn2mbH5GUzlH9TSHyfZpHkSiG1W7y3sF2Q= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw= +github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -301,8 +303,6 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= -github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM= -github.com/streadway/amqp v1.1.0/go.mod h1:WYSrTEYHOXHd0nwFeUXAe2G2hRnQT+deZJJf88uS9Bg= 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/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -348,6 +348,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.0.0-20181029175232-7e6ffbd03851/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 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= diff --git a/internal/notif/amqp/client.go b/internal/notif/amqp/client.go index f2a6f9939..afe5991bd 100644 --- a/internal/notif/amqp/client.go +++ b/internal/notif/amqp/client.go @@ -7,7 +7,7 @@ import ( "github.com/crazy-max/diun/v4/internal/msg" "github.com/crazy-max/diun/v4/internal/notif/notifier" "github.com/crazy-max/diun/v4/pkg/utl" - "github.com/streadway/amqp" + amqp "github.com/rabbitmq/amqp091-go" ) // Client represents an active amqp notification object diff --git a/vendor/github.com/rabbitmq/amqp091-go/.gitignore b/vendor/github.com/rabbitmq/amqp091-go/.gitignore new file mode 100644 index 000000000..a93cced22 --- /dev/null +++ b/vendor/github.com/rabbitmq/amqp091-go/.gitignore @@ -0,0 +1,6 @@ +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 new file mode 100644 index 000000000..4341bcf98 --- /dev/null +++ b/vendor/github.com/rabbitmq/amqp091-go/.golangci.yml @@ -0,0 +1,3 @@ +run: + build-tags: + - integration diff --git a/vendor/github.com/rabbitmq/amqp091-go/CHANGELOG.md b/vendor/github.com/rabbitmq/amqp091-go/CHANGELOG.md new file mode 100644 index 000000000..fd03c1f9b --- /dev/null +++ b/vendor/github.com/rabbitmq/amqp091-go/CHANGELOG.md @@ -0,0 +1,363 @@ +# Changelog + +## [v1.10.0](https://github.com/rabbitmq/amqp091-go/tree/v1.10.0) (2024-05-08) + +[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.9.0...v1.10.0) + +**Implemented enhancements:** + +- Undeprecate non-context publish functions [\#259](https://github.com/rabbitmq/amqp091-go/pull/259) ([Zerpet](https://github.com/Zerpet)) +- Update Go directive [\#257](https://github.com/rabbitmq/amqp091-go/pull/257) ([Zerpet](https://github.com/Zerpet)) + +**Fixed bugs:** + +- republishing on reconnect bug in the example [\#249](https://github.com/rabbitmq/amqp091-go/issues/249) +- Channel Notify Close not receive event when connection is closed by RMQ server. [\#241](https://github.com/rabbitmq/amqp091-go/issues/241) +- Inconsistent documentation [\#231](https://github.com/rabbitmq/amqp091-go/issues/231) +- Data race in the client example [\#72](https://github.com/rabbitmq/amqp091-go/issues/72) +- Fix string function of URI [\#258](https://github.com/rabbitmq/amqp091-go/pull/258) ([Zerpet](https://github.com/Zerpet)) + +**Closed issues:** + +- Documentation needed \(`PublishWithContext` does not use context\) [\#195](https://github.com/rabbitmq/amqp091-go/issues/195) +- concurrent dispatch data race [\#226](https://github.com/rabbitmq/amqp091-go/issues/226) + +**Merged pull requests:** + +- Fix data race in example [\#260](https://github.com/rabbitmq/amqp091-go/pull/260) ([Zerpet](https://github.com/Zerpet)) +- Address CodeQL warning [\#252](https://github.com/rabbitmq/amqp091-go/pull/252) ([lukebakken](https://github.com/lukebakken)) +- Add support for additional AMQP URI query parameters [\#251](https://github.com/rabbitmq/amqp091-go/pull/251) ([vilius-g](https://github.com/vilius-g)) +- Example fix [\#250](https://github.com/rabbitmq/amqp091-go/pull/250) ([Boris-Plato](https://github.com/Boris-Plato)) +- Increasing the code coverage [\#248](https://github.com/rabbitmq/amqp091-go/pull/248) ([edercarloscosta](https://github.com/edercarloscosta)) +- Use correct mutex to guard confirms.published [\#240](https://github.com/rabbitmq/amqp091-go/pull/240) ([hjr265](https://github.com/hjr265)) +- Documenting Publishing.Expiration usage [\#232](https://github.com/rabbitmq/amqp091-go/pull/232) ([niksteff](https://github.com/niksteff)) +- fix comment typo in example\_client\_test.go [\#228](https://github.com/rabbitmq/amqp091-go/pull/228) ([wisaTong](https://github.com/wisaTong)) +- Bump go.uber.org/goleak from 1.2.1 to 1.3.0 [\#227](https://github.com/rabbitmq/amqp091-go/pull/227) ([dependabot[bot]](https://github.com/apps/dependabot)) + +## [v1.9.0](https://github.com/rabbitmq/amqp091-go/tree/v1.9.0) (2023-10-02) + +[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.8.1...v1.9.0) + +**Implemented enhancements:** + +- Use of buffered delivery channels when prefetch\_count is not null [\#200](https://github.com/rabbitmq/amqp091-go/issues/200) + +**Fixed bugs:** + +- connection block when write connection reset by peer [\#222](https://github.com/rabbitmq/amqp091-go/issues/222) +- Test failure on 32bit architectures [\#202](https://github.com/rabbitmq/amqp091-go/issues/202) + +**Closed issues:** + +- Add a constant to set consumer timeout as queue argument [\#201](https://github.com/rabbitmq/amqp091-go/issues/201) +- Add a constant for CQ version [\#199](https://github.com/rabbitmq/amqp091-go/issues/199) +- Examples may need to be updated after \#140 [\#153](https://github.com/rabbitmq/amqp091-go/issues/153) + +**Merged pull requests:** + +- Update spec091.go [\#224](https://github.com/rabbitmq/amqp091-go/pull/224) ([pinkfish](https://github.com/pinkfish)) +- Closes 222 [\#223](https://github.com/rabbitmq/amqp091-go/pull/223) ([yywing](https://github.com/yywing)) +- Update write.go [\#221](https://github.com/rabbitmq/amqp091-go/pull/221) ([pinkfish](https://github.com/pinkfish)) +- Bump versions [\#219](https://github.com/rabbitmq/amqp091-go/pull/219) ([lukebakken](https://github.com/lukebakken)) +- remove extra word 'accept' from ExchangeDeclare description [\#217](https://github.com/rabbitmq/amqp091-go/pull/217) ([a-sabzian](https://github.com/a-sabzian)) +- Misc Windows CI updates [\#216](https://github.com/rabbitmq/amqp091-go/pull/216) ([lukebakken](https://github.com/lukebakken)) +- Stop using deprecated Publish function [\#207](https://github.com/rabbitmq/amqp091-go/pull/207) ([Zerpet](https://github.com/Zerpet)) +- Constant for consumer timeout queue argument [\#206](https://github.com/rabbitmq/amqp091-go/pull/206) ([Zerpet](https://github.com/Zerpet)) +- Add a constant for CQ v2 queue argument [\#205](https://github.com/rabbitmq/amqp091-go/pull/205) ([Zerpet](https://github.com/Zerpet)) +- Fix example for 32-bit compatibility [\#204](https://github.com/rabbitmq/amqp091-go/pull/204) ([Zerpet](https://github.com/Zerpet)) +- Fix to increase timeout milliseconds since it's too tight [\#203](https://github.com/rabbitmq/amqp091-go/pull/203) ([t2y](https://github.com/t2y)) +- Add Channel.ConsumeWithContext to be able to cancel delivering [\#192](https://github.com/rabbitmq/amqp091-go/pull/192) ([t2y](https://github.com/t2y)) + +## [v1.8.1](https://github.com/rabbitmq/amqp091-go/tree/v1.8.1) (2023-05-04) + +[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.8.0...v1.8.1) + +**Fixed bugs:** + +- Fixed incorrect version reported in client properties [52ce2efd03c53dcf77d5496977da46840e9abd24](https://github.com/rabbitmq/amqp091-go/commit/52ce2efd03c53dcf77d5496977da46840e9abd24) + +**Merged pull requests:** + +- Fix Example Client not reconnecting [\#186](https://github.com/rabbitmq/amqp091-go/pull/186) ([frankfil](https://github.com/frankfil)) + +## [v1.8.0](https://github.com/rabbitmq/amqp091-go/tree/v1.8.0) (2023-03-21) + +[Full Changelog](https://github.com/rabbitmq/amqp091-go/compare/v1.7.0...v1.8.0) + +**Closed issues:** + +- memory leak [\#179](https://github.com/rabbitmq/amqp091-go/issues/179) +- the publishWithContext interface will not return when it times out [\#178](https://github.com/rabbitmq/amqp091-go/issues/178) + +**Merged pull requests:** + +- Fix race condition on confirms [\#183](https://github.com/rabbitmq/amqp091-go/pull/183) ([calloway-jacob](https://github.com/calloway-jacob)) +- Add a CloseDeadline function to Connection [\#181](https://github.com/rabbitmq/amqp091-go/pull/181) ([Zerpet](https://github.com/Zerpet)) +- Fix memory leaks [\#180](https://github.com/rabbitmq/amqp091-go/pull/180) ([GXKe](https://github.com/GXKe)) +- Bump go.uber.org/goleak from 1.2.0 to 1.2.1 [\#177](https://github.com/rabbitmq/amqp091-go/pull/177) ([dependabot[bot]](https://github.com/apps/dependabot)) + +## [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 new file mode 100644 index 000000000..24b567590 --- /dev/null +++ b/vendor/github.com/rabbitmq/amqp091-go/CODE_OF_CONDUCT.md @@ -0,0 +1,77 @@ +# 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 new file mode 100644 index 000000000..ec86fe54c --- /dev/null +++ b/vendor/github.com/rabbitmq/amqp091-go/CONTRIBUTING.md @@ -0,0 +1,62 @@ +# 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/streadway/amqp/LICENSE b/vendor/github.com/rabbitmq/amqp091-go/LICENSE similarity index 89% rename from vendor/github.com/streadway/amqp/LICENSE rename to vendor/github.com/rabbitmq/amqp091-go/LICENSE index 07b89680a..72fa55ebc 100644 --- a/vendor/github.com/streadway/amqp/LICENSE +++ b/vendor/github.com/rabbitmq/amqp091-go/LICENSE @@ -1,5 +1,7 @@ -Copyright (c) 2012-2019, Sean Treadway, SoundCloud Ltd. -All rights reserved. +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: diff --git a/vendor/github.com/rabbitmq/amqp091-go/Makefile b/vendor/github.com/rabbitmq/amqp091-go/Makefile new file mode 100644 index 000000000..7dc71bc5f --- /dev/null +++ b/vendor/github.com/rabbitmq/amqp091-go/Makefile @@ -0,0 +1,57 @@ +.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) + +certs: + ./certs.sh + +.PHONY: certs-rm +certs-rm: + rm -r ./certs/ + +.PHONY: rabbitmq-server-tls +rabbitmq-server-tls: | certs ## 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 5671:5671 --publish 15672:15672 \ + --mount type=bind,src=./certs/server,dst=/certs \ + --mount type=bind,src=./certs/ca/cacert.pem,dst=/certs/cacert.pem,readonly \ + --mount type=bind,src=./rabbitmq-confs/tls/90-tls.conf,dst=/etc/rabbitmq/conf.d/90-tls.conf \ + --pull always rabbitmq:3-management diff --git a/vendor/github.com/rabbitmq/amqp091-go/README.md b/vendor/github.com/rabbitmq/amqp091-go/README.md new file mode 100644 index 000000000..6d3143f67 --- /dev/null +++ b/vendor/github.com/rabbitmq/amqp091-go/README.md @@ -0,0 +1,105 @@ +# 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 new file mode 100644 index 000000000..1378d6886 --- /dev/null +++ b/vendor/github.com/rabbitmq/amqp091-go/RELEASE.md @@ -0,0 +1,16 @@ +# Guide to release a new version + +1. Update the `buildVersion` constant in [connection.go](https://github.com/rabbitmq/amqp091-go/blob/4886c35d10b273bd374e3ed2356144ad41d27940/connection.go#L31) +2. Commit and push. Include the version in the commit message e.g. [this commit](https://github.com/rabbitmq/amqp091-go/commit/52ce2efd03c53dcf77d5496977da46840e9abd24) +3. Create a new [GitHub Release](https://github.com/rabbitmq/amqp091-go/releases). Create a new tag as `v..` + 1. Use auto-generate release notes feature in GitHub +4. Generate the change log, see [Changelog Generation](#changelog-generation) +5. Review the changelog. Watch out for issues closed as "not-fixed" or without a PR +6. Commit and Push. Pro-tip: include `[skip ci]` in the commit message to skip the CI run, since it's only documentation +7. Send an announcement to the mailing list. Take inspiration from [this message](https://groups.google.com/g/rabbitmq-users/c/EBGYGOWiSgs/m/0sSFuAGICwAJ) + +## Changelog Generation + +``` +github_changelog_generator --token GITHUB-TOKEN -u rabbitmq -p amqp091-go --no-unreleased --release-branch main +``` diff --git a/vendor/github.com/streadway/amqp/allocator.go b/vendor/github.com/rabbitmq/amqp091-go/allocator.go similarity index 71% rename from vendor/github.com/streadway/amqp/allocator.go rename to vendor/github.com/rabbitmq/amqp091-go/allocator.go index 53620e7d0..f2925e742 100644 --- a/vendor/github.com/streadway/amqp/allocator.go +++ b/vendor/github.com/rabbitmq/amqp091-go/allocator.go @@ -1,4 +1,9 @@ -package amqp +// 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" @@ -13,10 +18,10 @@ const ( // allocator maintains a bitset of allocated numbers. type allocator struct { - pool *big.Int - last int - low int - high int + pool *big.Int + follow int + low int + high int } // NewAllocator reserves and frees integers out of a range between low and @@ -26,10 +31,10 @@ type allocator struct { // sizeof(big.Word) func newAllocator(low, high int) *allocator { return &allocator{ - pool: big.NewInt(0), - last: low, - low: low, - high: high, + pool: big.NewInt(0), + follow: low, + low: low, + high: high, } } @@ -64,21 +69,29 @@ func (a allocator) String() string { // 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 + wrapped := a.follow + defer func() { + // make a.follow point to next value + if a.follow == a.high { + a.follow = a.low + } else { + a.follow += 1 + } + }() // Find trailing bit - for ; a.last <= a.high; a.last++ { - if a.reserve(a.last) { - return a.last, true + for ; a.follow <= a.high; a.follow++ { + if a.reserve(a.follow) { + return a.follow, true } } // Find preceding free'd pool - a.last = a.low + a.follow = a.low - for ; a.last < wrapped; a.last++ { - if a.reserve(a.last) { - return a.last, true + for ; a.follow < wrapped; a.follow++ { + if a.reserve(a.follow) { + return a.follow, true } } diff --git a/vendor/github.com/streadway/amqp/auth.go b/vendor/github.com/rabbitmq/amqp091-go/auth.go similarity index 63% rename from vendor/github.com/streadway/amqp/auth.go rename to vendor/github.com/rabbitmq/amqp091-go/auth.go index 435c94b12..0c07bb3ec 100644 --- a/vendor/github.com/streadway/amqp/auth.go +++ b/vendor/github.com/rabbitmq/amqp091-go/auth.go @@ -1,11 +1,12 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. +// 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. -// Source code and contact info at http://github.com/streadway/amqp -package amqp +package amqp091 import ( + "bytes" "fmt" ) @@ -43,13 +44,33 @@ func (auth *AMQPlainAuth) Mechanism() string { return "AMQPLAIN" } -// Response returns the null character delimited encoding for the SASL PLAIN Mechanism. +// Response returns an AMQP encoded credentials table, without the field table size. func (auth *AMQPlainAuth) Response() string { - return fmt.Sprintf("LOGIN:%sPASSWORD:%s", auth.Username, auth.Password) + 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 { diff --git a/vendor/github.com/streadway/amqp/certs.sh b/vendor/github.com/rabbitmq/amqp091-go/certs.sh similarity index 93% rename from vendor/github.com/streadway/amqp/certs.sh rename to vendor/github.com/rabbitmq/amqp091-go/certs.sh index 834f42242..0bbb1c6c0 100644 --- a/vendor/github.com/streadway/amqp/certs.sh +++ b/vendor/github.com/rabbitmq/amqp091-go/certs.sh @@ -38,7 +38,7 @@ serial = $dir/serial default_crl_days = 7 default_days = 3650 -default_md = sha1 +default_md = sha256 policy = testca_policy x509_extensions = certificate_extensions @@ -57,7 +57,7 @@ basicConstraints = CA:false [ req ] default_bits = 2048 default_keyfile = ./private/cakey.pem -default_md = sha1 +default_md = sha256 prompt = yes distinguished_name = root_ca_distinguished_name x509_extensions = root_ca_extensions @@ -71,12 +71,12 @@ keyUsage = keyCertSign, cRLSign [ client_ca_extensions ] basicConstraints = CA:false -keyUsage = digitalSignature +keyUsage = keyEncipherment,digitalSignature extendedKeyUsage = 1.3.6.1.5.5.7.3.2 [ server_ca_extensions ] basicConstraints = CA:false -keyUsage = keyEncipherment +keyUsage = keyEncipherment,digitalSignature extendedKeyUsage = 1.3.6.1.5.5.7.3.1 subjectAltName = @alt_names @@ -106,7 +106,7 @@ openssl req \ -new \ -nodes \ -config openssl.cnf \ - -subj "/CN=127.0.0.1/O=server/" \ + -subj "/CN=localhost/O=server/" \ -key $root/server/key.pem \ -out $root/server/req.pem \ -outform PEM @@ -115,7 +115,7 @@ openssl req \ -new \ -nodes \ -config openssl.cnf \ - -subj "/CN=127.0.0.1/O=client/" \ + -subj "/CN=localhost/O=client/" \ -key $root/client/key.pem \ -out $root/client/req.pem \ -outform PEM diff --git a/vendor/github.com/rabbitmq/amqp091-go/change_version.sh b/vendor/github.com/rabbitmq/amqp091-go/change_version.sh new file mode 100644 index 000000000..ff8e3694c --- /dev/null +++ b/vendor/github.com/rabbitmq/amqp091-go/change_version.sh @@ -0,0 +1,4 @@ +#!/bin/bash +echo $1 > VERSION +sed -i -e "s/.*buildVersion = \"*.*/buildVersion = \"$1\"/" ./connection.go +go fmt ./... diff --git a/vendor/github.com/streadway/amqp/channel.go b/vendor/github.com/rabbitmq/amqp091-go/channel.go similarity index 77% rename from vendor/github.com/streadway/amqp/channel.go rename to vendor/github.com/rabbitmq/amqp091-go/channel.go index cd19ce7ee..3dfd7faf9 100644 --- a/vendor/github.com/streadway/amqp/channel.go +++ b/vendor/github.com/rabbitmq/amqp091-go/channel.go @@ -1,11 +1,12 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. +// 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. -// Source code and contact info at http://github.com/streadway/amqp -package amqp +package amqp091 import ( + "context" "reflect" "sync" "sync/atomic" @@ -15,14 +16,14 @@ import ( // +------+---------+-------------+ +------------+ +-----------+ // | type | channel | size | | payload | | frame-end | // +------+---------+-------------+ +------------+ +-----------+ -// octet short long size octets octet +// +// 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 @@ -39,6 +40,7 @@ type Channel struct { // closed is set to 1 when the channel has been closed - see Channel.send() closed int32 + close chan struct{} // true when we will never notify again noNotify bool @@ -66,7 +68,7 @@ type Channel struct { errors chan *Error // State machine that manages frame order, must only be mutated by the connection - recv func(*Channel, frame) error + recv func(*Channel, frame) // Current state for frame re-assembly, only mutated from recv message messageWithContent @@ -84,12 +86,20 @@ func newChannel(c *Connection, id uint16) *Channel { confirms: newConfirms(), recv: (*Channel).recvMethod, errors: make(chan *Error, 1), + close: make(chan struct{}), } } +// 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() @@ -103,14 +113,7 @@ func (ch *Channel) shutdown(e *Error) { for _, c := range ch.closes { c <- e } - } - - // Signal that from now on, Channel.send() should call - // Channel.sendClosed() - atomic.StoreInt32(&ch.closed, 1) - - // Notify RPC if we're selecting - if e != nil { + // Notify RPC if we're selecting ch.errors <- e } @@ -144,6 +147,7 @@ func (ch *Channel) shutdown(e *Error) { } close(ch.errors) + close(ch.close) ch.noNotify = true }) } @@ -154,7 +158,7 @@ func (ch *Channel) shutdown(e *Error) { // 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 atomic.LoadInt32(&ch.closed) == 1 { + if ch.IsClosed() { return ch.sendClosed(msg) } @@ -230,14 +234,38 @@ func (ch *Channel) sendOpen(msg message) (err error) { size = len(body) } - if err = ch.connection.send(&methodFrame{ + // 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.send(&headerFrame{ + if err = ch.connection.sendUnflushed(&headerFrame{ ChannelId: ch.id, ClassId: class, Size: uint64(len(body)), @@ -252,7 +280,7 @@ func (ch *Channel) sendOpen(msg message) (err error) { j = len(body) } - if err = ch.connection.send(&bodyFrame{ + if err = ch.connection.sendUnflushed(&bodyFrame{ ChannelId: ch.id, Body: body[i:j], }); err != nil { @@ -260,6 +288,11 @@ func (ch *Channel) sendOpen(msg message) (err error) { } } } 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, @@ -274,11 +307,16 @@ func (ch *Channel) sendOpen(msg message) (err error) { 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() - ch.send(&channelCloseOk{}) + 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)) @@ -288,7 +326,9 @@ func (ch *Channel) dispatch(msg message) { c <- m.Active } ch.notifyM.RUnlock() - ch.send(&channelFlowOk{Active: m.Active}) + 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() @@ -330,44 +370,49 @@ func (ch *Channel) dispatch(msg message) { // deliveries are in flight and a no-wait cancel has happened default: - ch.rpc <- msg + select { + case <-ch.close: + return + case ch.rpc <- msg: + } } } -func (ch *Channel) transition(f func(*Channel, frame) error) error { +func (ch *Channel) transition(f func(*Channel, frame)) { ch.recv = f - return nil } -func (ch *Channel) recvMethod(f frame) error { +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 - return ch.transition((*Channel).recvHeader) + ch.transition((*Channel).recvHeader) + return } ch.dispatch(frame.Method) // termination state - return ch.transition((*Channel).recvMethod) + ch.transition((*Channel).recvMethod) case *headerFrame: // drop - return ch.transition((*Channel).recvMethod) + ch.transition((*Channel).recvMethod) case *bodyFrame: // drop - return ch.transition((*Channel).recvMethod) - } + ch.transition((*Channel).recvMethod) - panic("unexpected frame type") + default: + panic("unexpected frame type") + } } -func (ch *Channel) recvHeader(f frame) error { +func (ch *Channel) recvHeader(f frame) { switch frame := f.(type) { case *methodFrame: // interrupt content and handle method - return ch.recvMethod(f) + ch.recvMethod(f) case *headerFrame: // start collecting if we expect body frames @@ -376,29 +421,31 @@ func (ch *Channel) recvHeader(f frame) error { if frame.Size == 0 { ch.message.setContent(ch.header.Properties, ch.body) ch.dispatch(ch.message) // termination state - return ch.transition((*Channel).recvMethod) + ch.transition((*Channel).recvMethod) + return } - return ch.transition((*Channel).recvContent) + ch.transition((*Channel).recvContent) case *bodyFrame: // drop and reset - return ch.transition((*Channel).recvMethod) - } + ch.transition((*Channel).recvMethod) - panic("unexpected frame type") + 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) error { +func (ch *Channel) recvContent(f frame) { switch frame := f.(type) { case *methodFrame: // interrupt content and handle method - return ch.recvMethod(f) + ch.recvMethod(f) case *headerFrame: // drop and reset - return ch.transition((*Channel).recvMethod) + ch.transition((*Channel).recvMethod) case *bodyFrame: if cap(ch.body) == 0 { @@ -409,13 +456,15 @@ func (ch *Channel) recvContent(f frame) error { if uint64(len(ch.body)) >= ch.header.Size { ch.message.setContent(ch.header.Properties, ch.body) ch.dispatch(ch.message) // termination state - return ch.transition((*Channel).recvMethod) + ch.transition((*Channel).recvMethod) + return } - return ch.transition((*Channel).recvContent) - } + ch.transition((*Channel).recvContent) - panic("unexpected frame type") + default: + panic("unexpected frame type") + } } /* @@ -423,9 +472,12 @@ 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 { + if ch.IsClosed() { + return nil + } + defer ch.connection.closeChannel(ch, nil) return ch.call( &channelClose{ReplyCode: replySuccess}, @@ -433,6 +485,12 @@ func (ch *Channel) Close() error { ) } +// 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. @@ -443,6 +501,8 @@ 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() @@ -488,7 +548,6 @@ 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() @@ -510,7 +569,6 @@ 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() @@ -531,7 +589,6 @@ 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() @@ -594,6 +651,8 @@ 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() @@ -606,7 +665,6 @@ func (ch *Channel) NotifyPublish(confirm chan Confirmation) chan Confirmation { } return confirm - } /* @@ -672,7 +730,6 @@ 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{ @@ -705,12 +762,12 @@ 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("...")}) + QueueDeclare("alerts", true, false, false, false, nil) + Publish("", "alerts", false, false, Publishing{Body: []byte("...")}) - Delivery Exchange Key Queue - ----------------------------------------------- - key: alerts -> "" -> alerts -> alerts + 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. @@ -746,7 +803,6 @@ 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 { @@ -780,13 +836,11 @@ func (ch *Channel) QueueDeclare(name string, durable, autoDelete, exclusive, noW } /* - 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 { @@ -833,6 +887,7 @@ 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{ @@ -857,14 +912,14 @@ 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) + 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) + 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 @@ -874,16 +929,16 @@ 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 + 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 + 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 @@ -894,7 +949,6 @@ 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 { @@ -916,10 +970,6 @@ func (ch *Channel) QueueBind(name, key, exchange string, noWait bool, args Table /* 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 { @@ -976,7 +1026,6 @@ 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{ @@ -1043,11 +1092,11 @@ 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. +be dropped. RabbitMQ will requeue messages not acknowledged. In other words, dropped +messages in this way won't be lost. 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 @@ -1082,7 +1131,122 @@ func (ch *Channel) Consume(queue, consumer string, autoAck, exclusive, noLocal, return nil, err } - return (<-chan Delivery)(deliveries), nil + return deliveries, nil +} + +/* +ConsumeWithContext immediately starts delivering queued messages. + +This function is similar to Channel.Consume, and accepts a context to control +consumer lifecycle. When the context passed to this function is canceled, the +consumer associated with the deliveries channel will be canceled too. When the +context passed to this function is cancelled, the deliveries channel will be closed. + +An application is advised to keep on receiving messages from the delivery channel +until the channel is empty. This is specially important to avoid memory leaks from +unconsumed messages from the delivery channel. + +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, context is cancelled, 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. RabbitMQ will requeue messages not acknowledged. In other words, dropped +messages in this way won't be lost. +*/ +func (ch *Channel) ConsumeWithContext(ctx context.Context, 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{} + + select { + default: + case <-ctx.Done(): + return nil, ctx.Err() + } + + deliveries := make(chan Delivery) + + ch.consumers.add(consumer, deliveries) + + if err := ch.call(req, res); err != nil { + ch.consumers.cancel(consumer) + return nil, err + } + + go func() { + select { + case <-ch.consumers.closed: + return + case <-ctx.Done(): + if ch != nil { + _ = ch.Cancel(consumer, false) + } + } + }() + + return deliveries, nil } /* @@ -1126,7 +1290,7 @@ 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 declared as `internal` do not accept publishings. Internal exchanges are useful when you wish to implement inter-exchange topologies that should not be exposed to users of the broker. @@ -1158,13 +1322,11 @@ func (ch *Channel) ExchangeDeclare(name, kind string, durable, autoDelete, inter } /* - 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 { @@ -1227,14 +1389,14 @@ 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) + 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 + 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 @@ -1321,16 +1483,69 @@ 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) Publish(exchange, key string, mandatory, immediate bool, msg Publishing) error { + _, err := ch.PublishWithDeferredConfirm(exchange, key, mandatory, immediate, msg) + return err +} + +/* +PublishWithContext sends a Publishing from the client to an exchange on the server. + +NOTE: this function is equivalent to [Channel.Publish]. Context is not honoured. + +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(_ context.Context, exchange, key string, mandatory, immediate bool, msg Publishing) error { + return ch.Publish(exchange, key, mandatory, immediate, msg) +} + +/* +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. +*/ +func (ch *Channel) PublishWithDeferredConfirm(exchange, key string, mandatory, immediate bool, msg Publishing) (*DeferredConfirmation, error) { if err := msg.Headers.Validate(); err != nil { - return err + 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, @@ -1353,14 +1568,26 @@ func (ch *Channel) Publish(exchange, key string, mandatory, immediate bool, msg AppId: msg.AppId, }, }); err != nil { - return err + if ch.confirming { + ch.confirms.unpublish() + } + return nil, err } - if ch.confirming { - ch.confirms.Publish() - } + return dc, nil +} - return nil +/* +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. + +NOTE: PublishWithDeferredConfirmWithContext is equivalent to its non-context variant. The context passed +to this function is not honoured. +*/ +func (ch *Channel) PublishWithDeferredConfirmWithContext(_ context.Context, exchange, key string, mandatory, immediate bool, msg Publishing) (*DeferredConfirmation, error) { + return ch.PublishWithDeferredConfirm(exchange, key, mandatory, immediate, msg) } /* @@ -1379,7 +1606,6 @@ 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} @@ -1411,7 +1637,6 @@ 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( @@ -1425,7 +1650,6 @@ 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( @@ -1439,7 +1663,6 @@ 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( @@ -1469,7 +1692,6 @@ 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( @@ -1501,7 +1723,6 @@ 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( @@ -1530,6 +1751,11 @@ 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( @@ -1591,3 +1817,12 @@ func (ch *Channel) Reject(tag uint64, requeue bool) error { 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.publishedMut.Lock() + defer ch.confirms.publishedMut.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 new file mode 100644 index 000000000..577e042bc --- /dev/null +++ b/vendor/github.com/rabbitmq/amqp091-go/confirms.go @@ -0,0 +1,238 @@ +// 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/streadway/amqp/connection.go b/vendor/github.com/rabbitmq/amqp091-go/connection.go similarity index 62% rename from vendor/github.com/streadway/amqp/connection.go rename to vendor/github.com/rabbitmq/amqp091-go/connection.go index 252852e80..e167a23fc 100644 --- a/vendor/github.com/streadway/amqp/connection.go +++ b/vendor/github.com/rabbitmq/amqp091-go/connection.go @@ -1,15 +1,19 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. +// 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. -// Source code and contact info at http://github.com/streadway/amqp -package amqp +package amqp091 import ( "bufio" "crypto/tls" + "crypto/x509" + "errors" + "fmt" "io" "net" + "os" "reflect" "strconv" "strings" @@ -23,11 +27,12 @@ const ( defaultHeartbeat = 10 * time.Second defaultConnectionTimeout = 30 * time.Second - defaultProduct = "https://github.com/streadway/amqp" - defaultVersion = "β" + defaultProduct = "AMQP 0.9.1 Client" + buildVersion = "1.10.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 + defaultChannelMax = uint16((2 << 10) - 1) defaultLocale = "en_US" ) @@ -44,7 +49,7 @@ type Config struct { // 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 + ChannelMax uint16 // 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 @@ -71,6 +76,17 @@ type Config struct { 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 @@ -96,6 +112,8 @@ type Connection struct { blocks []chan Blocking errors chan *Error + // if connection is closed should close this chan + close chan struct{} Config Config // The negotiated Config after connection.open @@ -139,8 +157,7 @@ func DefaultDial(connectionTimeout time.Duration) func(network, addr string) (ne // scheme. It is equivalent to calling DialTLS(amqp, nil). func Dial(url string) (*Connection, error) { return DialConfig(url, Config{ - Heartbeat: defaultHeartbeat, - Locale: defaultLocale, + Locale: defaultLocale, }) } @@ -151,16 +168,33 @@ func Dial(url string) (*Connection, error) { // 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{ + 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. +// to 30 seconds. The heartbeat interval specified in the AMQP URI takes precedence +// over the value specified in the config. To disable heartbeats, you must use +// the AMQP URI and set heartbeat=0 there. func DialConfig(url string, config Config) (*Connection, error) { var err error var conn net.Conn @@ -171,18 +205,50 @@ func DialConfig(url string, config Config) (*Connection, error) { } if config.SASL == nil { - config.SASL = []Authentication{uri.PlainAuth()} + if uri.AuthMechanism != nil { + for _, identifier := range uri.AuthMechanism { + switch strings.ToUpper(identifier) { + case "PLAIN": + config.SASL = append(config.SASL, uri.PlainAuth()) + case "AMQPLAIN": + config.SASL = append(config.SASL, uri.AMQPlainAuth()) + case "EXTERNAL": + config.SASL = append(config.SASL, &ExternalAuth{}) + default: + return nil, fmt.Errorf("unsupported auth_mechanism: %v", identifier) + } + } + } else { + config.SASL = []Authentication{uri.PlainAuth()} + } } if config.Vhost == "" { config.Vhost = uri.Vhost } + if uri.Heartbeat.hasValue { + config.Heartbeat = uri.Heartbeat.value + } else { + if config.Heartbeat == 0 { + config.Heartbeat = defaultHeartbeat + } + } + + if config.ChannelMax == 0 { + config.ChannelMax = uri.ChannelMax + } + + connectionTimeout := defaultConnectionTimeout + if uri.ConnectionTimeout != 0 { + connectionTimeout = time.Duration(uri.ConnectionTimeout) * time.Millisecond + } + addr := net.JoinHostPort(uri.Host, strconv.FormatInt(int64(uri.Port), 10)) dialer := config.Dial if dialer == nil { - dialer = DefaultDial(defaultConnectionTimeout) + dialer = DefaultDial(connectionTimeout) } conn, err = dialer("tcp", addr) @@ -192,7 +258,11 @@ func DialConfig(url string, config Config) (*Connection, error) { if uri.Scheme == "amqps" { if config.TLSClientConfig == nil { - config.TLSClientConfig = new(tls.Config) + 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, @@ -203,7 +273,6 @@ func DialConfig(url string, config Config) (*Connection, error) { client := tls.Client(conn, config.TLSClientConfig) if err := client.Handshake(); err != nil { - conn.Close() return nil, err } @@ -218,7 +287,6 @@ func DialConfig(url string, config Config) (*Connection, error) { 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{ @@ -228,12 +296,29 @@ func Open(conn io.ReadWriteCloser, config Config) (*Connection, error) { rpc: make(chan message), sends: make(chan time.Time), errors: make(chan *Error, 1), + close: make(chan struct{}), 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(). @@ -247,6 +332,18 @@ func (c *Connection) LocalAddr() net.Addr { 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. @@ -263,11 +360,14 @@ func (c *Connection) ConnectionState() tls.ConnectionState { NotifyClose registers a listener for close events either initiated by an error accompanying a connection.close method or by a normal shutdown. -On normal shutdowns, the chan will be closed. +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() @@ -291,7 +391,6 @@ 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() @@ -334,12 +433,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), @@ -352,7 +486,19 @@ func (c *Connection) closeWith(err *Error) error { // 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) + 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 { @@ -383,6 +529,74 @@ func (c *Connection) send(f frame) error { 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) @@ -394,9 +608,6 @@ func (c *Connection) shutdown(err *Error) { for _, c := range c.closes { c <- err } - } - - if err != nil { c.errors <- err } // Shutdown handler goroutine can still receive the result. @@ -420,9 +631,11 @@ func (c *Connection) shutdown(err *Error) { } c.conn.Close() + // reader exit + close(c.close) - c.channels = map[uint16]*Channel{} - c.allocator = newAllocator(1, c.Config.ChannelMax) + c.channels = nil + c.allocator = nil c.noNotify = true }) } @@ -443,11 +656,10 @@ func (c *Connection) dispatch0(f frame) { switch m := mf.Method.(type) { case *connectionClose: // Send immediately as shutdown will close our side of the writer. - c.send(&methodFrame{ - ChannelId: 0, - Method: &connectionCloseOk{}, - }) - + 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 { @@ -458,22 +670,39 @@ func (c *Connection) dispatch0(f frame) { c <- Blocking{Active: false} } default: - c.rpc <- m + select { + case <-c.close: + return + case 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 - c.closeWith(ErrUnexpectedFrame) + // closeWith use call don't block reader + go func() { + 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 := c.channels[f.channel()] + 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() - if channel != nil { + // 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) @@ -496,15 +725,20 @@ func (c *Connection) dispatchClosed(f frame) { if mf, ok := f.(*methodFrame); ok { switch mf.Method.(type) { case *channelClose: - c.send(&methodFrame{ - ChannelId: f.channel(), - Method: &channelCloseOk{}, - }) + 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 - c.closeWith(ErrClosed) + // closeWith use call don't block reader + go func() { + if err := c.closeWith(ErrClosed); err != nil { + Logger.Printf("error sending connectionCloseOk with ErrClosed, error: %+v", err) + } + }() } } } @@ -517,6 +751,8 @@ func (c *Connection) reader(r io.Reader) { frames := &reader{buf} conn, haveDeadliner := r.(readDeadliner) + defer close(c.rpc) + for { frame, err := frames.ReadFrame() @@ -576,7 +812,13 @@ func (c *Connection) heartbeater(interval time.Duration, done chan *Error) { // 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 { - conn.SetReadDeadline(time.Now().Add(maxServerHeartbeatsInFlight * interval)) + 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: @@ -618,12 +860,17 @@ func (c *Connection) allocateChannel() (*Channel, error) { // releaseChannel removes a channel from the registry as the final part of the // channel lifecycle -func (c *Connection) releaseChannel(id uint16) { +func (c *Connection) releaseChannel(ch *Channel) { c.m.Lock() defer c.m.Unlock() - delete(c.channels, id) - c.allocator.release(int(id)) + if !c.IsClosed() { + got, ok := c.channels[ch.id] + if ok && got == ch { + delete(c.channels, ch.id) + c.allocator.release(int(ch.id)) + } + } } // openChannel allocates and opens a channel, must be paired with closeChannel @@ -634,7 +881,7 @@ func (c *Connection) openChannel() (*Channel, error) { } if err := ch.open(); err != nil { - c.releaseChannel(ch.id) + c.releaseChannel(ch) return nil, err } return ch, nil @@ -645,14 +892,13 @@ func (c *Connection) openChannel() (*Channel, error) { // this connection. func (c *Connection) closeChannel(ch *Channel, e *Error) { ch.shutdown(e) - c.releaseChannel(ch.id) + c.releaseChannel(ch) } /* 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() @@ -667,39 +913,46 @@ func (c *Connection) call(req message, res ...message) error { } } + var msg message select { - case err, ok := <-c.errors: - if !ok { - return ErrClosed + case e, ok := <-c.errors: + if ok { + return e } - return err + return ErrClosed + case msg = <-c.rpc: + } - case msg := <-c.rpc: - // 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 - } + // 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 } - // unreachable + return ErrCommandInvalid } -// 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 +// 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 @@ -717,7 +970,7 @@ func (c *Connection) openStart(config Config) error { c.Major = int(start.VersionMajor) c.Minor = int(start.VersionMinor) - c.Properties = Table(start.ServerProperties) + c.Properties = start.ServerProperties c.Locales = strings.Split(start.Locales, " ") // eventually support challenge/response here by also responding to @@ -738,15 +991,14 @@ func (c *Connection) openStart(config Config) error { func (c *Connection) openTune(config Config, auth Authentication) error { if len(config.Properties) == 0 { - config.Properties = Table{ - "product": defaultProduct, - "version": defaultVersion, - } + config.Properties = NewConnectionProperties() } config.Properties["capabilities"] = Table{ "connection.blocked": true, "consumer_cancel_notify": true, + "basic.nack": true, + "publisher_confirms": true, } ok := &connectionStartOk{ @@ -764,13 +1016,21 @@ func (c *Connection) openTune(config Config, auth Authentication) 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)) + c.Config.ChannelMax = pickUInt16(config.ChannelMax, tune.ChannelMax) if c.Config.ChannelMax == 0 { c.Config.ChannelMax = defaultChannelMax } - c.Config.ChannelMax = min(c.Config.ChannelMax, maxChannelMax) + c.Config.ChannelMax = minUInt16(c.Config.ChannelMax, maxChannelMax) + + c.allocator = newAllocator(1, int(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 @@ -784,7 +1044,7 @@ func (c *Connection) openTune(config Config, auth Authentication) error { // "The client should start sending heartbeats after receiving a // Connection.Tune method" - go c.heartbeater(c.Config.Heartbeat, c.NotifyClose(make(chan *Error, 1))) + go c.heartbeater(c.Config.Heartbeat/2, c.NotifyClose(make(chan *Error, 1))) if err := c.send(&methodFrame{ ChannelId: 0, @@ -826,10 +1086,48 @@ func (c *Connection) openComplete() error { _ = deadliner.SetDeadline(time.Time{}) } - c.allocator = newAllocator(1, c.Config.ChannelMax) 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 @@ -837,6 +1135,13 @@ func max(a, b int) int { return b } +func maxUInt16(a, b uint16) uint16 { + if a > b { + return a + } + return b +} + func min(a, b int) int { if a < b { return a @@ -844,6 +1149,21 @@ func min(a, b int) int { return b } +func minUInt16(a, b uint16) uint16 { + if a < b { + return a + } + return b +} + +func pickUInt16(client, server uint16) uint16 { + if client == 0 || server == 0 { + return maxUInt16(client, server) + } else { + return minUInt16(client, server) + } +} + func pick(client, server int) int { if client == 0 || server == 0 { return max(client, server) diff --git a/vendor/github.com/streadway/amqp/consumers.go b/vendor/github.com/rabbitmq/amqp091-go/consumers.go similarity index 65% rename from vendor/github.com/streadway/amqp/consumers.go rename to vendor/github.com/rabbitmq/amqp091-go/consumers.go index 887ac7494..c352fece9 100644 --- a/vendor/github.com/streadway/amqp/consumers.go +++ b/vendor/github.com/rabbitmq/amqp091-go/consumers.go @@ -1,9 +1,9 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. +// 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. -// Source code and contact info at http://github.com/streadway/amqp -package amqp +package amqp091 import ( "os" @@ -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/streadway/amqp/delivery.go b/vendor/github.com/rabbitmq/amqp091-go/delivery.go similarity index 96% rename from vendor/github.com/streadway/amqp/delivery.go rename to vendor/github.com/rabbitmq/amqp091-go/delivery.go index 724126442..e94cf3437 100644 --- a/vendor/github.com/streadway/amqp/delivery.go +++ b/vendor/github.com/rabbitmq/amqp091-go/delivery.go @@ -1,9 +1,9 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. +// 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. -// Source code and contact info at http://github.com/streadway/amqp -package amqp +package amqp091 import ( "errors" @@ -13,7 +13,7 @@ import ( var errDeliveryNotInitialized = errors.New("delivery not initialized") // Acknowledger notifies the server of successful or failed consumption of -// delivieries via identifier found in the Delivery.DeliveryTag field. +// deliveries via identifier found in the Delivery.DeliveryTag field. // // Applications can provide mock implementations in tests of Delivery handlers. type Acknowledger interface { diff --git a/vendor/github.com/rabbitmq/amqp091-go/doc.go b/vendor/github.com/rabbitmq/amqp091-go/doc.go new file mode 100644 index 000000000..461173fcc --- /dev/null +++ b/vendor/github.com/rabbitmq/amqp091-go/doc.go @@ -0,0 +1,160 @@ +// 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. 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, 1)) + +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 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. 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) + } + } + } + }() + +It is strongly recommended to use buffered channels to avoid deadlocks inside +the library. + +# 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 new file mode 100644 index 000000000..c9f03ea4e --- /dev/null +++ b/vendor/github.com/rabbitmq/amqp091-go/fuzz.go @@ -0,0 +1,23 @@ +// 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.ps1 b/vendor/github.com/rabbitmq/amqp091-go/gen.ps1 new file mode 100644 index 000000000..c93354316 --- /dev/null +++ b/vendor/github.com/rabbitmq/amqp091-go/gen.ps1 @@ -0,0 +1,14 @@ +$DebugPreference = 'Continue' +$ErrorActionPreference = 'Stop' + +Set-PSDebug -Off +Set-StrictMode -Version 'Latest' -ErrorAction 'Stop' -Verbose + +New-Variable -Name curdir -Option Constant -Value $PSScriptRoot + +$specDir = Resolve-Path -LiteralPath (Join-Path -Path $curdir -ChildPath 'spec') +$amqpSpecXml = Resolve-Path -LiteralPath (Join-Path -Path $specDir -ChildPath 'amqp0-9-1.stripped.extended.xml') +$gen = Resolve-Path -LiteralPath (Join-Path -Path $specDir -ChildPath 'gen.go') +$spec091 = Resolve-Path -LiteralPath (Join-Path -Path $curdir -ChildPath 'spec091.go') + +Get-Content -LiteralPath $amqpSpecXml | go run $gen | gofmt | Set-Content -Force -Path $spec091 diff --git a/vendor/github.com/streadway/amqp/gen.sh b/vendor/github.com/rabbitmq/amqp091-go/gen.sh similarity index 100% rename from vendor/github.com/streadway/amqp/gen.sh rename to vendor/github.com/rabbitmq/amqp091-go/gen.sh diff --git a/vendor/github.com/rabbitmq/amqp091-go/log.go b/vendor/github.com/rabbitmq/amqp091-go/log.go new file mode 100644 index 000000000..7540f137a --- /dev/null +++ b/vendor/github.com/rabbitmq/amqp091-go/log.go @@ -0,0 +1,23 @@ +// 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/streadway/amqp/read.go b/vendor/github.com/rabbitmq/amqp091-go/read.go similarity index 83% rename from vendor/github.com/streadway/amqp/read.go rename to vendor/github.com/rabbitmq/amqp091-go/read.go index 3aa0b3381..a8bed1379 100644 --- a/vendor/github.com/streadway/amqp/read.go +++ b/vendor/github.com/rabbitmq/amqp091-go/read.go @@ -1,9 +1,9 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. +// 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. -// Source code and contact info at http://github.com/streadway/amqp -package amqp +package amqp091 import ( "bytes" @@ -14,29 +14,29 @@ import ( ) /* -Reads a frame from an input stream and returns an interface that can be cast into +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 + 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 + 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. + 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 @@ -50,7 +50,7 @@ func (r *reader) ReadFrame() (frame frame, err error) { return } - typ := uint8(scratch[0]) + typ := scratch[0] channel := binary.BigEndian.Uint16(scratch[1:3]) size := binary.BigEndian.Uint32(scratch[3:7]) @@ -131,20 +131,6 @@ func readDecimal(r io.Reader) (v Decimal, err error) { return } -func readFloat32(r io.Reader) (v float32, err error) { - if err = binary.Read(r, binary.BigEndian, &v); err != nil { - return - } - return -} - -func readFloat64(r io.Reader) (v float64, err error) { - if err = binary.Read(r, binary.BigEndian, &v); 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 { @@ -161,7 +147,8 @@ func readTimestamp(r io.Reader) (v time.Time, err error) { 'S': string 'T': time.Time 'V': nil -'b': byte +'b': int8 +'B': byte 'd': float64 'f': float32 'l': int64 @@ -181,15 +168,22 @@ func readField(r io.Reader) (v interface{}, err error) { if err = binary.Read(r, binary.BigEndian, &value); err != nil { return } - return (value != 0), nil + return value != 0, nil - case 'b': + 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 { @@ -260,12 +254,12 @@ func readField(r io.Reader) (v interface{}, err error) { } /* - 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. +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 @@ -309,7 +303,7 @@ func readArray(r io.Reader) ([]interface{}, error) { var ( lim = &io.LimitedReader{R: r, N: int64(size)} - arr = []interface{}{} + arr []interface{} field interface{} ) diff --git a/vendor/github.com/streadway/amqp/return.go b/vendor/github.com/rabbitmq/amqp091-go/return.go similarity index 93% rename from vendor/github.com/streadway/amqp/return.go rename to vendor/github.com/rabbitmq/amqp091-go/return.go index 10dcedb2c..cdc3875ed 100644 --- a/vendor/github.com/streadway/amqp/return.go +++ b/vendor/github.com/rabbitmq/amqp091-go/return.go @@ -1,9 +1,9 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. +// 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. -// Source code and contact info at http://github.com/streadway/amqp -package amqp +package amqp091 import ( "time" diff --git a/vendor/github.com/streadway/amqp/spec091.go b/vendor/github.com/rabbitmq/amqp091-go/spec091.go similarity index 92% rename from vendor/github.com/streadway/amqp/spec091.go rename to vendor/github.com/rabbitmq/amqp091-go/spec091.go index cd53ebe74..6e02ba997 100644 --- a/vendor/github.com/streadway/amqp/spec091.go +++ b/vendor/github.com/rabbitmq/amqp091-go/spec091.go @@ -1,12 +1,12 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. +// 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. -// Source code and contact info at http://github.com/streadway/amqp /* GENERATED FILE - DO NOT EDIT */ /* Rebuild from the spec/gen.go tool */ -package amqp +package amqp091 import ( "encoding/binary" @@ -552,6 +552,66 @@ 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 } @@ -2757,7 +2817,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err switch mf.MethodId { case 10: // connection start - //fmt.Println("NextMethod: class:10 method:10") + // fmt.Println("NextMethod: class:10 method:10") method := &connectionStart{} if err = method.read(r.r); err != nil { return @@ -2765,7 +2825,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 11: // connection start-ok - //fmt.Println("NextMethod: class:10 method:11") + // fmt.Println("NextMethod: class:10 method:11") method := &connectionStartOk{} if err = method.read(r.r); err != nil { return @@ -2773,7 +2833,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 20: // connection secure - //fmt.Println("NextMethod: class:10 method:20") + // fmt.Println("NextMethod: class:10 method:20") method := &connectionSecure{} if err = method.read(r.r); err != nil { return @@ -2781,7 +2841,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 21: // connection secure-ok - //fmt.Println("NextMethod: class:10 method:21") + // fmt.Println("NextMethod: class:10 method:21") method := &connectionSecureOk{} if err = method.read(r.r); err != nil { return @@ -2789,7 +2849,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 30: // connection tune - //fmt.Println("NextMethod: class:10 method:30") + // fmt.Println("NextMethod: class:10 method:30") method := &connectionTune{} if err = method.read(r.r); err != nil { return @@ -2797,7 +2857,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 31: // connection tune-ok - //fmt.Println("NextMethod: class:10 method:31") + // fmt.Println("NextMethod: class:10 method:31") method := &connectionTuneOk{} if err = method.read(r.r); err != nil { return @@ -2805,7 +2865,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 40: // connection open - //fmt.Println("NextMethod: class:10 method:40") + // fmt.Println("NextMethod: class:10 method:40") method := &connectionOpen{} if err = method.read(r.r); err != nil { return @@ -2813,7 +2873,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 41: // connection open-ok - //fmt.Println("NextMethod: class:10 method:41") + // fmt.Println("NextMethod: class:10 method:41") method := &connectionOpenOk{} if err = method.read(r.r); err != nil { return @@ -2821,7 +2881,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 50: // connection close - //fmt.Println("NextMethod: class:10 method:50") + // fmt.Println("NextMethod: class:10 method:50") method := &connectionClose{} if err = method.read(r.r); err != nil { return @@ -2829,7 +2889,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 51: // connection close-ok - //fmt.Println("NextMethod: class:10 method:51") + // fmt.Println("NextMethod: class:10 method:51") method := &connectionCloseOk{} if err = method.read(r.r); err != nil { return @@ -2837,7 +2897,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 60: // connection blocked - //fmt.Println("NextMethod: class:10 method:60") + // fmt.Println("NextMethod: class:10 method:60") method := &connectionBlocked{} if err = method.read(r.r); err != nil { return @@ -2845,13 +2905,29 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 61: // connection unblocked - //fmt.Println("NextMethod: class:10 method:61") + // 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) } @@ -2860,7 +2936,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err switch mf.MethodId { case 10: // channel open - //fmt.Println("NextMethod: class:20 method:10") + // fmt.Println("NextMethod: class:20 method:10") method := &channelOpen{} if err = method.read(r.r); err != nil { return @@ -2868,7 +2944,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 11: // channel open-ok - //fmt.Println("NextMethod: class:20 method:11") + // fmt.Println("NextMethod: class:20 method:11") method := &channelOpenOk{} if err = method.read(r.r); err != nil { return @@ -2876,7 +2952,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 20: // channel flow - //fmt.Println("NextMethod: class:20 method:20") + // fmt.Println("NextMethod: class:20 method:20") method := &channelFlow{} if err = method.read(r.r); err != nil { return @@ -2884,7 +2960,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 21: // channel flow-ok - //fmt.Println("NextMethod: class:20 method:21") + // fmt.Println("NextMethod: class:20 method:21") method := &channelFlowOk{} if err = method.read(r.r); err != nil { return @@ -2892,7 +2968,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 40: // channel close - //fmt.Println("NextMethod: class:20 method:40") + // fmt.Println("NextMethod: class:20 method:40") method := &channelClose{} if err = method.read(r.r); err != nil { return @@ -2900,7 +2976,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 41: // channel close-ok - //fmt.Println("NextMethod: class:20 method:41") + // fmt.Println("NextMethod: class:20 method:41") method := &channelCloseOk{} if err = method.read(r.r); err != nil { return @@ -2915,7 +2991,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err switch mf.MethodId { case 10: // exchange declare - //fmt.Println("NextMethod: class:40 method:10") + // fmt.Println("NextMethod: class:40 method:10") method := &exchangeDeclare{} if err = method.read(r.r); err != nil { return @@ -2923,7 +2999,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 11: // exchange declare-ok - //fmt.Println("NextMethod: class:40 method:11") + // fmt.Println("NextMethod: class:40 method:11") method := &exchangeDeclareOk{} if err = method.read(r.r); err != nil { return @@ -2931,7 +3007,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 20: // exchange delete - //fmt.Println("NextMethod: class:40 method:20") + // fmt.Println("NextMethod: class:40 method:20") method := &exchangeDelete{} if err = method.read(r.r); err != nil { return @@ -2939,7 +3015,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 21: // exchange delete-ok - //fmt.Println("NextMethod: class:40 method:21") + // fmt.Println("NextMethod: class:40 method:21") method := &exchangeDeleteOk{} if err = method.read(r.r); err != nil { return @@ -2947,7 +3023,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 30: // exchange bind - //fmt.Println("NextMethod: class:40 method:30") + // fmt.Println("NextMethod: class:40 method:30") method := &exchangeBind{} if err = method.read(r.r); err != nil { return @@ -2955,7 +3031,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 31: // exchange bind-ok - //fmt.Println("NextMethod: class:40 method:31") + // fmt.Println("NextMethod: class:40 method:31") method := &exchangeBindOk{} if err = method.read(r.r); err != nil { return @@ -2963,7 +3039,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 40: // exchange unbind - //fmt.Println("NextMethod: class:40 method:40") + // fmt.Println("NextMethod: class:40 method:40") method := &exchangeUnbind{} if err = method.read(r.r); err != nil { return @@ -2971,7 +3047,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 51: // exchange unbind-ok - //fmt.Println("NextMethod: class:40 method:51") + // fmt.Println("NextMethod: class:40 method:51") method := &exchangeUnbindOk{} if err = method.read(r.r); err != nil { return @@ -2986,7 +3062,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err switch mf.MethodId { case 10: // queue declare - //fmt.Println("NextMethod: class:50 method:10") + // fmt.Println("NextMethod: class:50 method:10") method := &queueDeclare{} if err = method.read(r.r); err != nil { return @@ -2994,7 +3070,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 11: // queue declare-ok - //fmt.Println("NextMethod: class:50 method:11") + // fmt.Println("NextMethod: class:50 method:11") method := &queueDeclareOk{} if err = method.read(r.r); err != nil { return @@ -3002,7 +3078,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 20: // queue bind - //fmt.Println("NextMethod: class:50 method:20") + // fmt.Println("NextMethod: class:50 method:20") method := &queueBind{} if err = method.read(r.r); err != nil { return @@ -3010,7 +3086,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 21: // queue bind-ok - //fmt.Println("NextMethod: class:50 method:21") + // fmt.Println("NextMethod: class:50 method:21") method := &queueBindOk{} if err = method.read(r.r); err != nil { return @@ -3018,7 +3094,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 50: // queue unbind - //fmt.Println("NextMethod: class:50 method:50") + // fmt.Println("NextMethod: class:50 method:50") method := &queueUnbind{} if err = method.read(r.r); err != nil { return @@ -3026,7 +3102,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 51: // queue unbind-ok - //fmt.Println("NextMethod: class:50 method:51") + // fmt.Println("NextMethod: class:50 method:51") method := &queueUnbindOk{} if err = method.read(r.r); err != nil { return @@ -3034,7 +3110,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 30: // queue purge - //fmt.Println("NextMethod: class:50 method:30") + // fmt.Println("NextMethod: class:50 method:30") method := &queuePurge{} if err = method.read(r.r); err != nil { return @@ -3042,7 +3118,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 31: // queue purge-ok - //fmt.Println("NextMethod: class:50 method:31") + // fmt.Println("NextMethod: class:50 method:31") method := &queuePurgeOk{} if err = method.read(r.r); err != nil { return @@ -3050,7 +3126,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 40: // queue delete - //fmt.Println("NextMethod: class:50 method:40") + // fmt.Println("NextMethod: class:50 method:40") method := &queueDelete{} if err = method.read(r.r); err != nil { return @@ -3058,7 +3134,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 41: // queue delete-ok - //fmt.Println("NextMethod: class:50 method:41") + // fmt.Println("NextMethod: class:50 method:41") method := &queueDeleteOk{} if err = method.read(r.r); err != nil { return @@ -3073,7 +3149,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err switch mf.MethodId { case 10: // basic qos - //fmt.Println("NextMethod: class:60 method:10") + // fmt.Println("NextMethod: class:60 method:10") method := &basicQos{} if err = method.read(r.r); err != nil { return @@ -3081,7 +3157,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 11: // basic qos-ok - //fmt.Println("NextMethod: class:60 method:11") + // fmt.Println("NextMethod: class:60 method:11") method := &basicQosOk{} if err = method.read(r.r); err != nil { return @@ -3089,7 +3165,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 20: // basic consume - //fmt.Println("NextMethod: class:60 method:20") + // fmt.Println("NextMethod: class:60 method:20") method := &basicConsume{} if err = method.read(r.r); err != nil { return @@ -3097,7 +3173,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 21: // basic consume-ok - //fmt.Println("NextMethod: class:60 method:21") + // fmt.Println("NextMethod: class:60 method:21") method := &basicConsumeOk{} if err = method.read(r.r); err != nil { return @@ -3105,7 +3181,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 30: // basic cancel - //fmt.Println("NextMethod: class:60 method:30") + // fmt.Println("NextMethod: class:60 method:30") method := &basicCancel{} if err = method.read(r.r); err != nil { return @@ -3113,7 +3189,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 31: // basic cancel-ok - //fmt.Println("NextMethod: class:60 method:31") + // fmt.Println("NextMethod: class:60 method:31") method := &basicCancelOk{} if err = method.read(r.r); err != nil { return @@ -3121,7 +3197,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 40: // basic publish - //fmt.Println("NextMethod: class:60 method:40") + // fmt.Println("NextMethod: class:60 method:40") method := &basicPublish{} if err = method.read(r.r); err != nil { return @@ -3129,7 +3205,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 50: // basic return - //fmt.Println("NextMethod: class:60 method:50") + // fmt.Println("NextMethod: class:60 method:50") method := &basicReturn{} if err = method.read(r.r); err != nil { return @@ -3137,7 +3213,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 60: // basic deliver - //fmt.Println("NextMethod: class:60 method:60") + // fmt.Println("NextMethod: class:60 method:60") method := &basicDeliver{} if err = method.read(r.r); err != nil { return @@ -3145,7 +3221,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 70: // basic get - //fmt.Println("NextMethod: class:60 method:70") + // fmt.Println("NextMethod: class:60 method:70") method := &basicGet{} if err = method.read(r.r); err != nil { return @@ -3153,7 +3229,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 71: // basic get-ok - //fmt.Println("NextMethod: class:60 method:71") + // fmt.Println("NextMethod: class:60 method:71") method := &basicGetOk{} if err = method.read(r.r); err != nil { return @@ -3161,7 +3237,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 72: // basic get-empty - //fmt.Println("NextMethod: class:60 method:72") + // fmt.Println("NextMethod: class:60 method:72") method := &basicGetEmpty{} if err = method.read(r.r); err != nil { return @@ -3169,7 +3245,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 80: // basic ack - //fmt.Println("NextMethod: class:60 method:80") + // fmt.Println("NextMethod: class:60 method:80") method := &basicAck{} if err = method.read(r.r); err != nil { return @@ -3177,7 +3253,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 90: // basic reject - //fmt.Println("NextMethod: class:60 method:90") + // fmt.Println("NextMethod: class:60 method:90") method := &basicReject{} if err = method.read(r.r); err != nil { return @@ -3185,7 +3261,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 100: // basic recover-async - //fmt.Println("NextMethod: class:60 method:100") + // fmt.Println("NextMethod: class:60 method:100") method := &basicRecoverAsync{} if err = method.read(r.r); err != nil { return @@ -3193,7 +3269,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 110: // basic recover - //fmt.Println("NextMethod: class:60 method:110") + // fmt.Println("NextMethod: class:60 method:110") method := &basicRecover{} if err = method.read(r.r); err != nil { return @@ -3201,7 +3277,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 111: // basic recover-ok - //fmt.Println("NextMethod: class:60 method:111") + // fmt.Println("NextMethod: class:60 method:111") method := &basicRecoverOk{} if err = method.read(r.r); err != nil { return @@ -3209,7 +3285,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 120: // basic nack - //fmt.Println("NextMethod: class:60 method:120") + // fmt.Println("NextMethod: class:60 method:120") method := &basicNack{} if err = method.read(r.r); err != nil { return @@ -3224,7 +3300,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err switch mf.MethodId { case 10: // tx select - //fmt.Println("NextMethod: class:90 method:10") + // fmt.Println("NextMethod: class:90 method:10") method := &txSelect{} if err = method.read(r.r); err != nil { return @@ -3232,7 +3308,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 11: // tx select-ok - //fmt.Println("NextMethod: class:90 method:11") + // fmt.Println("NextMethod: class:90 method:11") method := &txSelectOk{} if err = method.read(r.r); err != nil { return @@ -3240,7 +3316,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 20: // tx commit - //fmt.Println("NextMethod: class:90 method:20") + // fmt.Println("NextMethod: class:90 method:20") method := &txCommit{} if err = method.read(r.r); err != nil { return @@ -3248,7 +3324,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 21: // tx commit-ok - //fmt.Println("NextMethod: class:90 method:21") + // fmt.Println("NextMethod: class:90 method:21") method := &txCommitOk{} if err = method.read(r.r); err != nil { return @@ -3256,7 +3332,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 30: // tx rollback - //fmt.Println("NextMethod: class:90 method:30") + // fmt.Println("NextMethod: class:90 method:30") method := &txRollback{} if err = method.read(r.r); err != nil { return @@ -3264,7 +3340,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 31: // tx rollback-ok - //fmt.Println("NextMethod: class:90 method:31") + // fmt.Println("NextMethod: class:90 method:31") method := &txRollbackOk{} if err = method.read(r.r); err != nil { return @@ -3279,7 +3355,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err switch mf.MethodId { case 10: // confirm select - //fmt.Println("NextMethod: class:85 method:10") + // fmt.Println("NextMethod: class:85 method:10") method := &confirmSelect{} if err = method.read(r.r); err != nil { return @@ -3287,7 +3363,7 @@ func (r *reader) parseMethodFrame(channel uint16, size uint32) (f frame, err err mf.Method = method case 11: // confirm select-ok - //fmt.Println("NextMethod: class:85 method:11") + // fmt.Println("NextMethod: class:85 method:11") method := &confirmSelectOk{} if err = method.read(r.r); err != nil { return diff --git a/vendor/github.com/streadway/amqp/types.go b/vendor/github.com/rabbitmq/amqp091-go/types.go similarity index 57% rename from vendor/github.com/streadway/amqp/types.go rename to vendor/github.com/rabbitmq/amqp091-go/types.go index 83bd92f97..1e15ed0ab 100644 --- a/vendor/github.com/streadway/amqp/types.go +++ b/vendor/github.com/rabbitmq/amqp091-go/types.go @@ -1,9 +1,9 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. +// 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. -// Source code and contact info at http://github.com/streadway/amqp -package amqp +package amqp091 import ( "fmt" @@ -11,6 +11,10 @@ import ( "time" ) +// DefaultExchange is the default direct exchange that binds every queue by its +// name. Applications can route to a queue using the queue name as routing key. +const DefaultExchange = "" + // Constants for standard AMQP 0-9-1 exchange types. const ( ExchangeDirect = "direct" @@ -29,7 +33,7 @@ var ( ErrChannelMax = &Error{Code: ChannelError, Reason: "channel id space exhausted"} // ErrSASL is returned from Dial when the authentication mechanism could not - // be negoated. + // be negotiated. ErrSASL = &Error{Code: AccessRefused, Reason: "SASL could not negotiate a shared mechanism"} // ErrCredentials is returned when the authenticated client is not authorized @@ -61,6 +65,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 { @@ -135,6 +144,19 @@ const ( flagReserved1 = 0x0004 ) +// Expiration. These constants can be used to set a messages expiration TTL. +// They should be viewed as a clarification of the expiration functionality in +// messages and their usage is not enforced by this pkg. +// +// The server requires a string value that is interpreted by the server as +// milliseconds. If no value is set, which translates to the nil value of +// string, the message will never expire by itself. This does not influence queue +// configured TTL configurations. +const ( + NeverExpire string = "" // empty value means never expire + ImmediatelyExpire string = "0" // 0 means immediately expire +) + // Queue captures the current server state of the queue on the server returned // from Channel.QueueDeclare or Channel.QueueInspect. type Queue struct { @@ -153,18 +175,25 @@ type Publishing struct { 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 + 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 represents the message TTL in milliseconds. A value of "0" + // indicates that the message will immediately expire if the message arrives + // at its destination and the message is not directly handled by a consumer + // that currently has the capacatity to do so. If you wish the message to + // not expire on its own, set this value to any ttl value, empty string or + // use the corresponding constants NeverExpire and ImmediatelyExpire. This + // does not influence queue configured TTL values. + Expiration string + 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 @@ -179,6 +208,16 @@ type Blocking struct { 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. @@ -194,23 +233,106 @@ type Decimal struct { 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 +// +// Starting with RabbitMQ 3.12, consumer timeout can be configured as a queue +// argument. This is the timeout for a consumer to acknowledge a message. The +// value is the time in milliseconds. The timeout is evaluated periodically, +// at one minute intervals. Values lower than one minute are not supported. +// See the [consumer timeout] guide for more information. +// +// [Single Active Consumer] on quorum and classic queues can be configured +// using [SingleActiveConsumerArg]. This argument expects a boolean value. It is +// false by default. +// +// [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 +// [consumer timeout]: https://rabbitmq.com/consumers.html#acknowledgement-timeout +// [Single Active Consumer]: https://rabbitmq.com/consumers.html#single-active-consumer +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" + // QueueVersionArg declares the Classic Queue version to use. Expects an integer, either 1 or 2. + QueueVersionArg = "x-queue-version" + // ConsumerTimeoutArg is available in RabbitMQ 3.12+ as a queue argument. + ConsumerTimeoutArg = "x-consumer-timeout" + SingleActiveConsumerArg = "x-single-active-consumer" +) + +// 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, +// } +// +// Refer to [Channel.QueueDeclare] for more examples. +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 -// float32 -// float64 -// int -// int16 -// int32 -// int64 -// nil -// string -// time.Time -// amqp.Decimal -// amqp.Table -// []byte -// []interface{} - containing above 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. @@ -221,12 +343,11 @@ type Decimal struct { // 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, int, int16, int32, int64, float32, float64, string, []byte, Decimal, time.Time: + case nil, bool, byte, int8, int, int16, int32, int64, float32, float64, string, []byte, Decimal, time.Time: return nil case []interface{}: @@ -254,17 +375,12 @@ func (t Table) Validate() error { return validateField(t) } -// Heap interface for maintaining delivery tags -type tagSet []uint64 - -func (set tagSet) Len() int { return len(set) } -func (set tagSet) Less(i, j int) bool { return (set)[i] < (set)[j] } -func (set tagSet) Swap(i, j int) { (set)[i], (set)[j] = (set)[j], (set)[i] } -func (set *tagSet) Push(tag interface{}) { *set = append(*set, tag.(uint64)) } -func (set *tagSet) Pop() interface{} { - val := (*set)[len(*set)-1] - *set = (*set)[:len(*set)-1] - return val +// 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 { @@ -288,11 +404,11 @@ The base interface implemented as: 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 + 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: @@ -303,13 +419,24 @@ To read a frame, we: 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 } @@ -334,17 +461,17 @@ func (protocolHeader) channel() uint16 { 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 ... + 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. + 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. @@ -383,11 +510,11 @@ 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... + 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 @@ -415,10 +542,10 @@ 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] - ... + [method] + [method] [header] [body] [body] + [method] + ... */ type bodyFrame struct { ChannelId uint16 @@ -426,3 +553,16 @@ type bodyFrame struct { } func (f *bodyFrame) channel() uint16 { return f.ChannelId } + +type heartbeatDuration struct { + value time.Duration + hasValue bool +} + +func newHeartbeatDurationFromSeconds(s int) heartbeatDuration { + v := time.Duration(s) * time.Second + return heartbeatDuration{ + value: v, + hasValue: true, + } +} diff --git a/vendor/github.com/streadway/amqp/uri.go b/vendor/github.com/rabbitmq/amqp091-go/uri.go similarity index 52% rename from vendor/github.com/streadway/amqp/uri.go rename to vendor/github.com/rabbitmq/amqp091-go/uri.go index e58471549..ddc4b1adb 100644 --- a/vendor/github.com/streadway/amqp/uri.go +++ b/vendor/github.com/rabbitmq/amqp091-go/uri.go @@ -1,12 +1,13 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. +// 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. -// Source code and contact info at http://github.com/streadway/amqp -package amqp +package amqp091 import ( "errors" + "fmt" "net" "net/url" "strconv" @@ -32,12 +33,20 @@ var defaultURI = URI{ // URI represents a parsed AMQP URI string. type URI struct { - Scheme string - Host string - Port int - Username string - Password string - Vhost string + 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 + AuthMechanism []string + Heartbeat heartbeatDuration + ConnectionTimeout int + ChannelMax uint16 } // ParseURI attempts to parse the given AMQP URI according to the spec. @@ -45,17 +54,32 @@ type URI struct { // // Default values for the fields are: // -// Scheme: amqp -// Host: localhost -// Port: 5672 -// Username: guest -// Password: guest -// Vhost: / +// 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: +// auth_mechanism: +// heartbeat: +// connection_timeout: +// channel_max: +// +// 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, " ") == true { + if strings.Contains(uri, " ") { return builder, errURIWhitespace } @@ -113,6 +137,38 @@ func ParseURI(uri string) (URI, error) { } } + // 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") + builder.AuthMechanism = params["auth_mechanism"] + + if params.Has("heartbeat") { + value, err := strconv.Atoi(params.Get("heartbeat")) + if err != nil { + return builder, fmt.Errorf("heartbeat is not an integer: %v", err) + } + builder.Heartbeat = newHeartbeatDurationFromSeconds(value) + } + + if params.Has("connection_timeout") { + value, err := strconv.Atoi(params.Get("connection_timeout")) + if err != nil { + return builder, fmt.Errorf("connection_timeout is not an integer: %v", err) + } + builder.ConnectionTimeout = value + } + + if params.Has("channel_max") { + value, err := strconv.ParseUint(params.Get("channel_max"), 10, 16) + if err != nil { + return builder, fmt.Errorf("connection_timeout is not an integer: %v", err) + } + builder.ChannelMax = uint16(value) + } + return builder, nil } @@ -150,8 +206,6 @@ func (uri URI) String() string { } } - authority.Host = net.JoinHostPort(uri.Host, strconv.Itoa(uri.Port)) - if defaultPort, found := schemePorts[uri.Scheme]; !found || defaultPort != uri.Port { authority.Host = net.JoinHostPort(uri.Host, strconv.Itoa(uri.Port)) } else { @@ -172,5 +226,29 @@ func (uri URI) String() string { authority.Path = "/" } + if uri.CertFile != "" || uri.KeyFile != "" || uri.CACertFile != "" || uri.ServerName != "" { + rawQuery := strings.Builder{} + if uri.CertFile != "" { + rawQuery.WriteString("certfile=") + rawQuery.WriteString(uri.CertFile) + rawQuery.WriteRune('&') + } + if uri.KeyFile != "" { + rawQuery.WriteString("keyfile=") + rawQuery.WriteString(uri.KeyFile) + rawQuery.WriteRune('&') + } + if uri.CACertFile != "" { + rawQuery.WriteString("cacertfile=") + rawQuery.WriteString(uri.CACertFile) + rawQuery.WriteRune('&') + } + if uri.ServerName != "" { + rawQuery.WriteString("server_name_indication=") + rawQuery.WriteString(uri.ServerName) + } + authority.RawQuery = rawQuery.String() + } + return authority.String() } diff --git a/vendor/github.com/streadway/amqp/write.go b/vendor/github.com/rabbitmq/amqp091-go/write.go similarity index 94% rename from vendor/github.com/streadway/amqp/write.go rename to vendor/github.com/rabbitmq/amqp091-go/write.go index 94a46d115..dcec31448 100644 --- a/vendor/github.com/streadway/amqp/write.go +++ b/vendor/github.com/rabbitmq/amqp091-go/write.go @@ -1,9 +1,9 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. +// 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. -// Source code and contact info at http://github.com/streadway/amqp -package amqp +package amqp091 import ( "bufio" @@ -15,6 +15,11 @@ import ( "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 @@ -63,11 +68,10 @@ func (f *heartbeatFrame) write(w io.Writer) (err error) { // +----------+--------+-----------+----------------+------------- - - // | class-id | weight | body size | property flags | property list... // +----------+--------+-----------+----------------+------------- - - -// short short long long short remainder... // +// 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 @@ -113,7 +117,7 @@ func (f *headerFrame) write(w io.Writer) (err error) { if len(f.Properties.MessageId) > 0 { mask = mask | flagMessageId } - if f.Properties.Timestamp != zeroTime { + if !f.Properties.Timestamp.IsZero() { mask = mask | flagTimestamp } if len(f.Properties.Type) > 0 { @@ -212,7 +216,7 @@ func writeFrame(w io.Writer, typ uint8, channel uint16, payload []byte) (err err size := uint(len(payload)) _, err = w.Write([]byte{ - byte(typ), + typ, byte((channel & 0xff00) >> 8), byte((channel & 0x00ff) >> 0), byte((size & 0xff000000) >> 24), @@ -276,7 +280,8 @@ func writeLongstr(w io.Writer, s string) (err error) { 'S': string 'T': time.Time 'V': nil -'b': byte +'b': int8 +'B': byte 'd': float64 'f': float32 'l': int64 @@ -299,8 +304,13 @@ func writeField(w io.Writer, value interface{}) (err error) { enc = buf[:2] case byte: + buf[0] = 'B' + buf[1] = v + enc = buf[:2] + + case int8: buf[0] = 'b' - buf[1] = byte(v) + buf[1] = uint8(v) enc = buf[:2] case int16: @@ -335,7 +345,7 @@ func writeField(w io.Writer, value interface{}) (err error) { case Decimal: buf[0] = 'D' - buf[1] = byte(v.Scale) + buf[1] = v.Scale binary.BigEndian.PutUint32(buf[2:6], uint32(v.Value)) enc = buf[:6] @@ -412,5 +422,5 @@ func writeTable(w io.Writer, table Table) (err error) { } } - return writeLongstr(w, string(buf.Bytes())) + return writeLongstr(w, buf.String()) } diff --git a/vendor/github.com/streadway/amqp/.gitignore b/vendor/github.com/streadway/amqp/.gitignore deleted file mode 100644 index 667fb50c5..000000000 --- a/vendor/github.com/streadway/amqp/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -certs/* -spec/spec -examples/simple-consumer/simple-consumer -examples/simple-producer/simple-producer - -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -.idea/**/contentModel.xml diff --git a/vendor/github.com/streadway/amqp/.travis.yml b/vendor/github.com/streadway/amqp/.travis.yml deleted file mode 100644 index 7eee262b4..000000000 --- a/vendor/github.com/streadway/amqp/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -language: go - -go: - - 1.10.x - - 1.11.x - - 1.12.x - - 1.13.x - -addons: - apt: - packages: - - rabbitmq-server - -services: - - rabbitmq - -env: - - GO111MODULE=on AMQP_URL=amqp://guest:guest@127.0.0.1:5672/ - -before_install: - - go get -v golang.org/x/lint/golint - -script: - - ./pre-commit - - go test -cpu=1,2 -v -tags integration ./... diff --git a/vendor/github.com/streadway/amqp/CONTRIBUTING.md b/vendor/github.com/streadway/amqp/CONTRIBUTING.md deleted file mode 100644 index c87f3d7e0..000000000 --- a/vendor/github.com/streadway/amqp/CONTRIBUTING.md +++ /dev/null @@ -1,35 +0,0 @@ -## Prequisites - -1. Go: [https://golang.org/dl/](https://golang.org/dl/) -1. Golint `go get -u -v github.com/golang/lint/golint` - -## Contributing - -The workflow is pretty standard: - -1. Fork github.com/streadway/amqp -1. Add the pre-commit hook: `ln -s ../../pre-commit .git/hooks/pre-commit` -1. Create your feature branch (`git checkout -b my-new-feature`) -1. Run integration tests (see below) -1. **Implement tests** -1. Implement fixs -1. Commit your changes (`git commit -am 'Add some feature'`) -1. Push to a branch (`git push -u origin my-new-feature`) -1. Submit a pull request - -## Running Tests - -The test suite assumes that: - - * A RabbitMQ node is running on localhost with all defaults: [https://www.rabbitmq.com/download.html](https://www.rabbitmq.com/download.html) - * `AMQP_URL` is exported to `amqp://guest:guest@127.0.0.1:5672/` - -### Integration Tests - -After starting a local RabbitMQ, run integration tests with the following: - - env AMQP_URL=amqp://guest:guest@127.0.0.1:5672/ go test -v -cpu 2 -tags integration -race - -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/streadway/amqp/README.md b/vendor/github.com/streadway/amqp/README.md deleted file mode 100644 index fd179dc29..000000000 --- a/vendor/github.com/streadway/amqp/README.md +++ /dev/null @@ -1,100 +0,0 @@ -[![Build Status](https://api.travis-ci.org/streadway/amqp.svg)](http://travis-ci.org/streadway/amqp) [![GoDoc](https://godoc.org/github.com/streadway/amqp?status.svg)](http://godoc.org/github.com/streadway/amqp) - -# Go RabbitMQ Client Library (Unmaintained Fork) - -## Beware of Abandonware - -This repository is **NOT ACTIVELY MAINTAINED**. Consider using -a different fork instead: [rabbitmq/amqp091-go](https://github.com/rabbitmq/amqp091-go). -In case of questions, start a discussion in that repo or [use other RabbitMQ community resources](https://rabbitmq.com/contact.html). - - - -## Project Maturity - -This project has been used in production systems for many years. As of 2022, -this repository is **NOT ACTIVELY MAINTAINED**. - -This repository is **very strict** about any potential public API changes. -You may want to consider [rabbitmq/amqp091-go](https://github.com/rabbitmq/amqp091-go) which -is more willing to adapt the API. - - -## Supported Go Versions - -This library supports two most recent Go release series, currently 1.10 and 1.11. - - -## Supported RabbitMQ Versions - -This project supports RabbitMQ versions starting with `2.0` but primarily tested -against reasonably recent `3.x` releases. 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. Versions 0.10 and 1.0 are divergent - specifications that change the semantics and wire format of the protocol. - We will accept patches for other protocol support but have no plans for - implementation ourselves. - * 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. - -## Usage - -See the '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 - -Use [Godoc documentation](http://godoc.org/github.com/streadway/amqp) for -reference and usage. - -[RabbitMQ tutorials in -Go](https://github.com/rabbitmq/rabbitmq-tutorials/tree/master/go) are also -available. - -## Contributing - -Pull requests are very much welcomed. Create your pull request on a non-master -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. - -To run the integration tests, make sure you have RabbitMQ running on any host, -export the environment variable `AMQP_URL=amqp://host/` and run `go test -tags -integration`. TravisCI will also run the integration tests. - -Thanks to the [community of contributors](https://github.com/streadway/amqp/graphs/contributors). - -## External packages - - * [Google App Engine Dialer support](https://github.com/soundtrackyourbrand/gaeamqp) - * [RabbitMQ examples in Go](https://github.com/rabbitmq/rabbitmq-tutorials/tree/master/go) - -## License - -BSD 2 clause - see LICENSE for more details. - - diff --git a/vendor/github.com/streadway/amqp/confirms.go b/vendor/github.com/streadway/amqp/confirms.go deleted file mode 100644 index 06cbaa711..000000000 --- a/vendor/github.com/streadway/amqp/confirms.go +++ /dev/null @@ -1,94 +0,0 @@ -package amqp - -import "sync" - -// confirms resequences and notifies one or multiple publisher confirmation listeners -type confirms struct { - m sync.Mutex - listeners []chan Confirmation - sequencer map[uint64]Confirmation - published uint64 - expecting uint64 -} - -// newConfirms allocates a confirms -func newConfirms() *confirms { - return &confirms{ - sequencer: map[uint64]Confirmation{}, - 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() uint64 { - c.m.Lock() - defer c.m.Unlock() - - c.published++ - return 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() { - 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() - - 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() - - for c.expecting <= confirmed.DeliveryTag { - c.confirm(Confirmation{c.expecting, confirmed.Ack}) - } - c.resequence() -} - -// Close closes all listeners, discarding any out of sequence confirmations -func (c *confirms) Close() error { - c.m.Lock() - defer c.m.Unlock() - - for _, l := range c.listeners { - close(l) - } - c.listeners = nil - return nil -} diff --git a/vendor/github.com/streadway/amqp/doc.go b/vendor/github.com/streadway/amqp/doc.go deleted file mode 100644 index ee69c5b38..000000000 --- a/vendor/github.com/streadway/amqp/doc.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2012, Sean Treadway, SoundCloud Ltd. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// Source code and contact info at http://github.com/streadway/amqp - -/* -Package amqp 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 sychronous 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.Publish 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 - -*/ -package amqp diff --git a/vendor/github.com/streadway/amqp/fuzz.go b/vendor/github.com/streadway/amqp/fuzz.go deleted file mode 100644 index 16e626ce7..000000000 --- a/vendor/github.com/streadway/amqp/fuzz.go +++ /dev/null @@ -1,17 +0,0 @@ -// +build gofuzz - -package amqp - -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/streadway/amqp/pre-commit b/vendor/github.com/streadway/amqp/pre-commit deleted file mode 100644 index 371553007..000000000 --- a/vendor/github.com/streadway/amqp/pre-commit +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/sh - -LATEST_STABLE_SUPPORTED_GO_VERSION="1.11" - -main() { - if local_go_version_is_latest_stable - then - run_gofmt - run_golint - run_govet - fi - run_unit_tests -} - -local_go_version_is_latest_stable() { - go version | grep -q $LATEST_STABLE_SUPPORTED_GO_VERSION -} - -log_error() { - echo "$*" 1>&2 -} - -run_gofmt() { - GOFMT_FILES=$(gofmt -l .) - if [ -n "$GOFMT_FILES" ] - then - log_error "gofmt failed for the following files: -$GOFMT_FILES - -please run 'gofmt -w .' on your changes before committing." - exit 1 - fi -} - -run_golint() { - GOLINT_ERRORS=$(golint ./... | grep -v "Id should be") - if [ -n "$GOLINT_ERRORS" ] - then - log_error "golint failed for the following reasons: -$GOLINT_ERRORS - -please run 'golint ./...' on your changes before committing." - exit 1 - fi -} - -run_govet() { - GOVET_ERRORS=$(go tool vet ./*.go 2>&1) - if [ -n "$GOVET_ERRORS" ] - then - log_error "go vet failed for the following reasons: -$GOVET_ERRORS - -please run 'go tool vet ./*.go' on your changes before committing." - exit 1 - fi -} - -run_unit_tests() { - if [ -z "$NOTEST" ] - then - log_error 'Running short tests...' - env AMQP_URL= go test -short - fi -} - -main diff --git a/vendor/modules.txt b/vendor/modules.txt index 1b40cd020..29a2cd03f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -401,6 +401,9 @@ github.com/pkg/profile # github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 ## explicit github.com/pmezard/go-difflib/difflib +# github.com/rabbitmq/amqp091-go v1.10.0 +## explicit; go 1.20 +github.com/rabbitmq/amqp091-go # github.com/rivo/uniseg v0.4.7 ## explicit; go 1.18 github.com/rivo/uniseg @@ -422,9 +425,6 @@ github.com/spf13/pflag # github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf ## explicit github.com/ssor/bom -# github.com/streadway/amqp v1.1.0 -## explicit; go 1.10 -github.com/streadway/amqp # github.com/stretchr/testify v1.9.0 ## explicit; go 1.17 github.com/stretchr/testify/assert