bbk-amqp 1.0.0.72904
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +154 -0
- data/README.md +38 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/lib/bbk/amqp/consumer.rb +118 -0
- data/lib/bbk/amqp/domains/by_block.rb +24 -0
- data/lib/bbk/amqp/domains/exchange.rb +22 -0
- data/lib/bbk/amqp/domains_set.rb +40 -0
- data/lib/bbk/amqp/message.rb +47 -0
- data/lib/bbk/amqp/publisher.rb +177 -0
- data/lib/bbk/amqp/route_info.rb +15 -0
- data/lib/bbk/amqp/spec/rabbit_helper.rb +68 -0
- data/lib/bbk/amqp/spec.rb +2 -0
- data/lib/bbk/amqp/utils.rb +113 -0
- data/lib/bbk/amqp/version.rb +10 -0
- data/lib/bbk/amqp.rb +32 -0
- data/lib/bbk/bunny_patch.rb +10 -0
- data/sig/bbk/amqp/consumer.rbs +26 -0
- data/sig/bbk/amqp/domains/by_block.rbs +12 -0
- data/sig/bbk/amqp/domains/common.rbs +10 -0
- data/sig/bbk/amqp/domains/exchange.rbs +14 -0
- data/sig/bbk/amqp/domains_set.rbs +13 -0
- data/sig/bbk/amqp/message.rbs +11 -0
- data/sig/bbk/amqp/publisher.rbs +31 -0
- data/sig/bbk/amqp/route_info.rbs +10 -0
- data/sig/bbk/amqp/utils.rbs +11 -0
- metadata +251 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4e0df2e2301de0e3ec42d3f12ce60b93321e206f0c1263318af185ca33487046
|
4
|
+
data.tar.gz: 371aa962df0e67a3215c551ada7f9538969d6662607ee812ad3cf1eb4ded83c6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 777ec22b1895c6b86bee77be39764b4b0f66558edaad57c26feb425fce556050fa15a75ef136368b6de79f8261475e40dfb6e2c4717c43481658c5eb4a019652
|
7
|
+
data.tar.gz: e06609cb88278b16c1ce1c9fe341d0694c492915fbdedc1c99e54fa1a3d0aeb9a169bc2e20e8b9ea4f511d6d1a97a3b46bab598d420eb2dacfa4030928f03928
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
bbk-amqp (1.0.0.72904)
|
5
|
+
activesupport (~> 6.0)
|
6
|
+
bbk-utils (> 1.0.1)
|
7
|
+
bunny (>= 2.19.0)
|
8
|
+
oj
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
activesupport (6.1.4.4)
|
14
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
15
|
+
i18n (>= 1.6, < 2)
|
16
|
+
minitest (>= 5.1)
|
17
|
+
tzinfo (~> 2.0)
|
18
|
+
zeitwerk (~> 2.3)
|
19
|
+
addressable (2.8.0)
|
20
|
+
public_suffix (>= 2.0.2, < 5.0)
|
21
|
+
amq-protocol (2.3.2)
|
22
|
+
ansi (1.5.0)
|
23
|
+
ast (2.4.2)
|
24
|
+
axiom-types (0.1.1)
|
25
|
+
descendants_tracker (~> 0.0.4)
|
26
|
+
ice_nine (~> 0.11.0)
|
27
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
28
|
+
bbk-app (1.0.0.72899)
|
29
|
+
activesupport
|
30
|
+
bbk-utils (> 1.0.1)
|
31
|
+
timeouter
|
32
|
+
bbk-utils (1.0.1.72735)
|
33
|
+
activesupport (~> 6.0)
|
34
|
+
russian
|
35
|
+
bunny (2.19.0)
|
36
|
+
amq-protocol (~> 2.3, >= 2.3.1)
|
37
|
+
sorted_set (~> 1, >= 1.0.2)
|
38
|
+
bunny-mock (1.7.0)
|
39
|
+
bunny (>= 1.7)
|
40
|
+
byebug (11.1.3)
|
41
|
+
coercible (1.0.0)
|
42
|
+
descendants_tracker (~> 0.0.1)
|
43
|
+
concurrent-ruby (1.1.9)
|
44
|
+
descendants_tracker (0.0.4)
|
45
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
46
|
+
diff-lcs (1.5.0)
|
47
|
+
docile (1.4.0)
|
48
|
+
equalizer (0.0.11)
|
49
|
+
erubis (2.7.0)
|
50
|
+
flay (2.12.1)
|
51
|
+
erubis (~> 2.7.0)
|
52
|
+
path_expander (~> 1.0)
|
53
|
+
ruby_parser (~> 3.0)
|
54
|
+
sexp_processor (~> 4.0)
|
55
|
+
flog (4.6.4)
|
56
|
+
path_expander (~> 1.0)
|
57
|
+
ruby_parser (~> 3.1, > 3.1.0)
|
58
|
+
sexp_processor (~> 4.8)
|
59
|
+
i18n (1.8.11)
|
60
|
+
concurrent-ruby (~> 1.0)
|
61
|
+
ice_nine (0.11.2)
|
62
|
+
kwalify (0.7.2)
|
63
|
+
launchy (2.5.0)
|
64
|
+
addressable (~> 2.7)
|
65
|
+
minitest (5.15.0)
|
66
|
+
oj (3.13.11)
|
67
|
+
parser (3.0.3.2)
|
68
|
+
ast (~> 2.4.1)
|
69
|
+
path_expander (1.1.0)
|
70
|
+
public_suffix (4.0.6)
|
71
|
+
rainbow (3.1.1)
|
72
|
+
rake (13.0.6)
|
73
|
+
rbtree (0.4.4)
|
74
|
+
reek (6.0.6)
|
75
|
+
kwalify (~> 0.7.0)
|
76
|
+
parser (~> 3.0.0)
|
77
|
+
rainbow (>= 2.0, < 4.0)
|
78
|
+
rspec (3.10.0)
|
79
|
+
rspec-core (~> 3.10.0)
|
80
|
+
rspec-expectations (~> 3.10.0)
|
81
|
+
rspec-mocks (~> 3.10.0)
|
82
|
+
rspec-core (3.10.1)
|
83
|
+
rspec-support (~> 3.10.0)
|
84
|
+
rspec-expectations (3.10.1)
|
85
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
86
|
+
rspec-support (~> 3.10.0)
|
87
|
+
rspec-mocks (3.10.2)
|
88
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
89
|
+
rspec-support (~> 3.10.0)
|
90
|
+
rspec-support (3.10.3)
|
91
|
+
rspec_junit_formatter (0.5.1)
|
92
|
+
rspec-core (>= 2, < 4, != 2.12.0)
|
93
|
+
ruby_parser (3.18.1)
|
94
|
+
sexp_processor (~> 4.16)
|
95
|
+
rubycritic (4.6.1)
|
96
|
+
flay (~> 2.8)
|
97
|
+
flog (~> 4.4)
|
98
|
+
launchy (>= 2.0.0)
|
99
|
+
parser (>= 2.6.0)
|
100
|
+
rainbow (~> 3.0)
|
101
|
+
reek (~> 6.0, < 7.0)
|
102
|
+
ruby_parser (~> 3.8)
|
103
|
+
simplecov (>= 0.17.0)
|
104
|
+
tty-which (~> 0.4.0)
|
105
|
+
virtus (~> 1.0)
|
106
|
+
russian (0.6.0)
|
107
|
+
i18n (>= 0.5.0)
|
108
|
+
set (1.0.2)
|
109
|
+
sexp_processor (4.16.0)
|
110
|
+
simplecov (0.21.2)
|
111
|
+
docile (~> 1.1)
|
112
|
+
simplecov-html (~> 0.11)
|
113
|
+
simplecov_json_formatter (~> 0.1)
|
114
|
+
simplecov-console (0.9.1)
|
115
|
+
ansi
|
116
|
+
simplecov
|
117
|
+
terminal-table
|
118
|
+
simplecov-html (0.12.3)
|
119
|
+
simplecov_json_formatter (0.1.3)
|
120
|
+
sorted_set (1.0.3)
|
121
|
+
rbtree
|
122
|
+
set (~> 1.0)
|
123
|
+
terminal-table (3.0.2)
|
124
|
+
unicode-display_width (>= 1.1.1, < 3)
|
125
|
+
thread_safe (0.3.6)
|
126
|
+
timeouter (0.1.3.38794)
|
127
|
+
tty-which (0.4.2)
|
128
|
+
tzinfo (2.0.4)
|
129
|
+
concurrent-ruby (~> 1.0)
|
130
|
+
unicode-display_width (2.1.0)
|
131
|
+
virtus (1.0.5)
|
132
|
+
axiom-types (~> 0.1)
|
133
|
+
coercible (~> 1.0)
|
134
|
+
descendants_tracker (~> 0.0, >= 0.0.3)
|
135
|
+
equalizer (~> 0.0, >= 0.0.9)
|
136
|
+
zeitwerk (2.5.3)
|
137
|
+
|
138
|
+
PLATFORMS
|
139
|
+
ruby
|
140
|
+
|
141
|
+
DEPENDENCIES
|
142
|
+
bbk-amqp!
|
143
|
+
bbk-app (>= 1.0.0)
|
144
|
+
bunny-mock
|
145
|
+
byebug
|
146
|
+
rake
|
147
|
+
rspec
|
148
|
+
rspec_junit_formatter
|
149
|
+
rubycritic
|
150
|
+
simplecov
|
151
|
+
simplecov-console
|
152
|
+
|
153
|
+
BUNDLED WITH
|
154
|
+
2.2.33
|
data/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# BBK::AMQP
|
2
|
+
|
3
|
+
AMQP interaction classes for BBK stack.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Adding to a gem:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
# my-cool-gem.gemspec
|
11
|
+
|
12
|
+
Gem::Specification.new do |spec|
|
13
|
+
# ...
|
14
|
+
spec.add_dependency "bbk-amqp", "~> 1.0.0"
|
15
|
+
# ...
|
16
|
+
end
|
17
|
+
```
|
18
|
+
|
19
|
+
Or adding to your project:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
# Gemfile
|
23
|
+
|
24
|
+
gem "bbk-amqp", "~> 1.0.0"
|
25
|
+
```
|
26
|
+
|
27
|
+
### Supported Ruby versions
|
28
|
+
|
29
|
+
* Ruby (MRI) >= 2.5.0
|
30
|
+
|
31
|
+
### Tested Ruby versions
|
32
|
+
|
33
|
+
* Ruby (MRI) 2.5.x
|
34
|
+
* Ruby (MRI) 3.0.x
|
35
|
+
|
36
|
+
## License
|
37
|
+
|
38
|
+
The gem is available as open source under the terms of the MIT License.
|
data/bin/console
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'bbk/amqp'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start(__FILE__)
|
16
|
+
|
data/bin/setup
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BBK
|
4
|
+
module AMQP
|
5
|
+
class Consumer
|
6
|
+
|
7
|
+
attr_reader :connection, :queue_name, :queue, :options, :logger
|
8
|
+
|
9
|
+
DEFAULT_OPTIONS = {
|
10
|
+
consumer_pool_size: 3,
|
11
|
+
consumer_pool_abort_on_exception: true,
|
12
|
+
prefetch_size: 10,
|
13
|
+
requeue_on_reject: false,
|
14
|
+
consumer_tag: nil
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
PROTOCOLS = %w[mq amqp amqps].freeze
|
18
|
+
|
19
|
+
def initialize(connection, queue_name: nil, **options)
|
20
|
+
@connection = connection
|
21
|
+
@channel = options.delete(:channel)
|
22
|
+
@queue = options.delete(:queue)
|
23
|
+
|
24
|
+
if @queue.nil? && queue_name.nil?
|
25
|
+
raise ArgumentError.new('queue_name or queue must be provided!')
|
26
|
+
end
|
27
|
+
|
28
|
+
@queue_name = @queue&.name || queue_name
|
29
|
+
|
30
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
31
|
+
|
32
|
+
logger = @options.fetch(:logger, BBK::AMQP.logger)
|
33
|
+
logger = logger.respond_to?(:tagged) ? logger : ActiveSupport::TaggedLogging.new(logger)
|
34
|
+
@logger = BBK::Utils::ProxyLogger.new(logger, tags: [self.class.to_s, queue_name])
|
35
|
+
end
|
36
|
+
|
37
|
+
# Return protocol list which consumer support
|
38
|
+
def protocols
|
39
|
+
PROTOCOLS
|
40
|
+
end
|
41
|
+
|
42
|
+
# Running non blocking consumer
|
43
|
+
# @param msg_stream [Enumerable] - object with << method
|
44
|
+
def run(msg_stream)
|
45
|
+
@channel ||= @connection.create_channel(nil, options[:consumer_pool_size],
|
46
|
+
options[:consumer_pool_abort_on_exception]).tap do |ch|
|
47
|
+
ch.prefetch(options[:prefetch_size])
|
48
|
+
end
|
49
|
+
|
50
|
+
@logger.add_tags "Ch##{@channel.id}"
|
51
|
+
|
52
|
+
@queue ||= @channel.queue(queue_name, passive: true)
|
53
|
+
|
54
|
+
subscribe_opts = {
|
55
|
+
block: false,
|
56
|
+
manual_ack: true,
|
57
|
+
consumer_tag: options[:consumer_tag]
|
58
|
+
}.compact
|
59
|
+
|
60
|
+
logger.info 'Starting...'
|
61
|
+
@subscription = queue.subscribe(subscribe_opts) do |delivery_info, metadata, payload|
|
62
|
+
message = Message.new(self, delivery_info, metadata, payload)
|
63
|
+
# logger.debug "Consumed message #{message.headers[:type]}[#{message.headers[:message_id]}] on channel: #{delivery_info.channel&.id}[#{delivery_info.channel&.object_id}] delivery tag: #{message.delivery_info[:delivery_tag].to_i}"
|
64
|
+
logger.debug "Consumed message #{message.headers[:type]}[#{message.headers[:message_id]}] delivery tag: #{message.delivery_info[:delivery_tag].to_i}"
|
65
|
+
|
66
|
+
msg_stream << message
|
67
|
+
end
|
68
|
+
msg_stream
|
69
|
+
end
|
70
|
+
|
71
|
+
# Ack incoming message and not send answer.
|
72
|
+
# @note answer should processing amqp publisher
|
73
|
+
# @param incoming [BBK::AMQP::Message] consumed message from amqp channel
|
74
|
+
# @param answer [BBK::App::Dispatcher::Result] answer message
|
75
|
+
def ack(incoming, *args, answer: nil, **kwargs)
|
76
|
+
# [] - для работы тестов. В реальности вернется объект VersionedDeliveryTag у
|
77
|
+
# которого to_i (вызывается внутри channel.ack) вернет фактическоe число
|
78
|
+
# logger.debug "Ack message #{incoming.headers[:type]}[#{incoming.headers[:message_id]}] on channel: #{incoming.delivery_info[:channel]&.id}[#{incoming.delivery_info[:channel]&.object_id}] delivery tag: #{incoming.delivery_info[:delivery_tag].to_i}"
|
79
|
+
logger.debug "Ack message #{incoming.headers[:type]}[#{incoming.headers[:message_id]}] delivery tag: #{incoming.delivery_info[:delivery_tag].to_i}"
|
80
|
+
incoming.delivery_info[:channel].ack incoming.delivery_info[:delivery_tag]
|
81
|
+
end
|
82
|
+
|
83
|
+
# Nack incoming message
|
84
|
+
# @param incoming [BBK::AMQP::Message] nack procesing message
|
85
|
+
def nack(incoming, *args, error: nil, requeue: nil, **_kwargs)
|
86
|
+
logger.debug "Reject message #{incoming.headers[:type]}[#{incoming.headers[:message_id]}] delivery tag: #{incoming.delivery_info[:delivery_tag].to_i}. Error: #{error.inspect}"
|
87
|
+
requeue_message = requeue.nil? ? options[:requeue_on_reject] : requeue
|
88
|
+
incoming.delivery_info[:channel].reject incoming.delivery_info[:delivery_tag],
|
89
|
+
requeue_message
|
90
|
+
end
|
91
|
+
|
92
|
+
# stop consuming messages
|
93
|
+
def stop
|
94
|
+
@subscription.tap do |s|
|
95
|
+
return nil unless s
|
96
|
+
|
97
|
+
logger.info 'Stopping...'
|
98
|
+
@subscription = nil
|
99
|
+
s.cancel
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Close consumer - try close amqp channel
|
104
|
+
def close
|
105
|
+
@channel.tap do |c|
|
106
|
+
return nil unless c
|
107
|
+
|
108
|
+
logger.info 'Closing...'
|
109
|
+
@channel = nil
|
110
|
+
c.close
|
111
|
+
logger.info 'Stopped'
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module BBK
|
2
|
+
module AMQP
|
3
|
+
module Domains
|
4
|
+
class ByBlock
|
5
|
+
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
def initialize(name, &block)
|
9
|
+
raise ArgumentError.new('no block') unless block_given?
|
10
|
+
|
11
|
+
@name = name
|
12
|
+
@block = block
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(route)
|
16
|
+
@block.call(route)
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module BBK
|
2
|
+
module AMQP
|
3
|
+
module Domains
|
4
|
+
class Exchange
|
5
|
+
|
6
|
+
|
7
|
+
attr_reader :name, :exchange
|
8
|
+
|
9
|
+
def initialize(name, exchange)
|
10
|
+
@name = name
|
11
|
+
@exchange = exchange
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(route)
|
15
|
+
BBK::AMQP::RouteInfo.new(exchange, route.routing_key)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BBK
|
4
|
+
module AMQP
|
5
|
+
# Store for amqp domains. Domain is pair: domain name and exchange name.
|
6
|
+
class DomainsSet
|
7
|
+
|
8
|
+
def initialize(*domains)
|
9
|
+
@domains = domains.map{|d| [d.name.to_s, d] }.to_h
|
10
|
+
end
|
11
|
+
|
12
|
+
# Get exchange name by domain
|
13
|
+
# @param domain_name [String] domain name
|
14
|
+
# @return [String] exchange name configured for passed domain name
|
15
|
+
def [](domain_name)
|
16
|
+
@domains[domain_name]
|
17
|
+
end
|
18
|
+
|
19
|
+
def add(domain)
|
20
|
+
@domains[domain.name.to_s] = domain
|
21
|
+
end
|
22
|
+
|
23
|
+
alias << add
|
24
|
+
|
25
|
+
# Each method implementation for object iteration
|
26
|
+
def each(&block)
|
27
|
+
@domains.values.each(&block)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Check if store has information about domain
|
31
|
+
# @param domain_name [String] domain name
|
32
|
+
# @return [Boolean] has information about domain
|
33
|
+
def has?(domain_name)
|
34
|
+
@domains.key? domain_name
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BBK
|
4
|
+
module AMQP
|
5
|
+
# Store information about consumed AMQP message
|
6
|
+
class Message
|
7
|
+
|
8
|
+
attr_reader :consumer, :headers, :body, :payload, :delivery_info, :properties
|
9
|
+
|
10
|
+
def initialize(consumer, delivery_info, properties, body)
|
11
|
+
@consumer = consumer
|
12
|
+
@properties = properties.to_h.with_indifferent_access
|
13
|
+
@body = body
|
14
|
+
amqp_consumer = delivery_info[:consumer]
|
15
|
+
@delivery_info = delivery_info.to_h.merge(
|
16
|
+
message_consumer: consumer,
|
17
|
+
protocols: consumer.protocols,
|
18
|
+
queue: amqp_consumer&.queue_name
|
19
|
+
)
|
20
|
+
@headers = @properties.except(:headers).merge(properties[:headers]).with_indifferent_access
|
21
|
+
@payload = begin
|
22
|
+
Oj.load(body).with_indifferent_access
|
23
|
+
rescue StandardError
|
24
|
+
{}.with_indifferent_access
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def message_id
|
29
|
+
headers[:message_id]
|
30
|
+
end
|
31
|
+
|
32
|
+
def reply_to
|
33
|
+
headers[:reply_to]
|
34
|
+
end
|
35
|
+
|
36
|
+
def ack(*args, answer: nil, **kwargs)
|
37
|
+
consumer.ack(self, *args, answer: answer, **kwargs)
|
38
|
+
end
|
39
|
+
|
40
|
+
def nack(*args, error: nil, **kwargs)
|
41
|
+
consumer.ack(self, *args, error: error, **kwargs)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
require 'concurrent'
|
5
|
+
|
6
|
+
module BBK
|
7
|
+
module AMQP
|
8
|
+
# Publisher send amqp messages
|
9
|
+
class Publisher
|
10
|
+
|
11
|
+
HEADER_PROP_FIELDS = %i[user_id message_id reply_to correlation_id].freeze
|
12
|
+
PROTOCOLS = %w[mq amqp amqps].freeze
|
13
|
+
|
14
|
+
attr_reader :connection, :domains, :logger, :channel, :ack_map, :sended_messages, :channel
|
15
|
+
|
16
|
+
def initialize(connection, domains, logger: BBK::AMQP.logger)
|
17
|
+
@connection = connection
|
18
|
+
@channel = connection.channel
|
19
|
+
@domains = domains
|
20
|
+
|
21
|
+
logger = logger.respond_to?(:tagged) ? logger : ActiveSupport::TaggedLogging.new(logger)
|
22
|
+
@logger = BBK::Utils::ProxyLogger.new(logger, tags: [self.class.to_s, "Ch##{@channel.id}"])
|
23
|
+
|
24
|
+
@ack_map = Concurrent::Map.new
|
25
|
+
@sended_messages = Concurrent::Map.new
|
26
|
+
@configured_exchanges = Set.new
|
27
|
+
initialize_callbacks
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returned supported protocols list
|
31
|
+
# @return [Array<Symbol>]
|
32
|
+
def protocols
|
33
|
+
PROTOCOLS
|
34
|
+
end
|
35
|
+
|
36
|
+
# Close publisher - try close amqp channel
|
37
|
+
def close
|
38
|
+
@channel.tap do |c|
|
39
|
+
return nil unless c
|
40
|
+
|
41
|
+
@channel = nil
|
42
|
+
c.close
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Publish dispatcher result
|
47
|
+
# @param result [BBK::App::Dispatcher::Result] sended result
|
48
|
+
def publish(result)
|
49
|
+
logger.debug "Try publish dispatcher result #{result.inspect}"
|
50
|
+
route = result.route
|
51
|
+
result_domain = route.domain
|
52
|
+
raise "Unsupported protocol #{route.scheme}" unless PROTOCOLS.include?(route.scheme)
|
53
|
+
raise "Unknown domain #{result_domain}" unless domains.has?(result_domain)
|
54
|
+
|
55
|
+
domain = domains[result_domain]
|
56
|
+
raise ArgumentError.new("Unknown route domain #{resutl_domain}") if domain.nil?
|
57
|
+
|
58
|
+
route_info = domain.call(route)
|
59
|
+
message = result.message
|
60
|
+
publish_message(route_info.routing_key, message, exchange: route_info.exchange)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Publish message
|
64
|
+
# @param routing_key [String] message routing key
|
65
|
+
# @param message [Object] (object with headers and payload method)
|
66
|
+
# @param exchange [Object] exchange for sending message
|
67
|
+
# @param options [Hash] message properties
|
68
|
+
def publish_message(routing_key, message, exchange:, options: {})
|
69
|
+
logger.debug "Try publish message #{message.headers.inspect}"
|
70
|
+
properties = {
|
71
|
+
persistent: true,
|
72
|
+
mandatory: true,
|
73
|
+
routing_key: routing_key,
|
74
|
+
headers: message.headers,
|
75
|
+
user_id: client_name, # если есть в headers, то на следующей строке будет перетерто
|
76
|
+
**message.headers.select {|k| HEADER_PROP_FIELDS.include? k }.compact
|
77
|
+
}.merge(options).symbolize_keys
|
78
|
+
send_message(exchange, routing_key, message.payload, properties)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Publish raw payload
|
82
|
+
# @param routing_key [String] routing key for sending data
|
83
|
+
# @param exchange [String] exchange name
|
84
|
+
# @param properties [Hash] amqp message properties
|
85
|
+
# @param headers [Messag]
|
86
|
+
def raw_publish(routing_key, exchange:, properties: {}, headers: {}, payload: {})
|
87
|
+
logger.debug "Publish raw message #{headers.inspect}"
|
88
|
+
properties = properties.deep_dup
|
89
|
+
properties[:headers] = properties.fetch(:headers, {}).merge headers
|
90
|
+
properties = properties.merge(headers.select do |k|
|
91
|
+
HEADER_PROP_FIELDS.include? k
|
92
|
+
end.compact).symbolize_keys
|
93
|
+
send_message(exchange, routing_key, payload, properties)
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
# Initialize amqp callbacks
|
99
|
+
def initialize_callbacks
|
100
|
+
@channel.confirm_select method(:on_confirm).curry(4).call(channel)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Configure on return callback for exchange
|
104
|
+
def configure_exchange(exchange_name)
|
105
|
+
return if @configured_exchanges.include?(exchange_name)
|
106
|
+
|
107
|
+
logger.debug "Configure on_return callback for exchange #{exchange_name}"
|
108
|
+
exchange = channel.exchange(exchange_name, passive: true)
|
109
|
+
exchange.on_return(&method(:on_return).curry(4).call(exchange))
|
110
|
+
@configured_exchanges << exchange_name
|
111
|
+
end
|
112
|
+
|
113
|
+
# Get connection user. If tls connectoin try extract CN from connection tls_cert
|
114
|
+
# @return [String] user name
|
115
|
+
def client_name
|
116
|
+
return connection.user unless connection.ssl?
|
117
|
+
|
118
|
+
@client_name ||= Utils.commonname(connection.transport.tls_certificate_path)
|
119
|
+
end
|
120
|
+
|
121
|
+
def on_return(exchange, basic_return, properties, body)
|
122
|
+
args = { exchange: exchange, basic_return: basic_return, properties: properties,
|
123
|
+
body: body }
|
124
|
+
message_id = properties[:message_id]
|
125
|
+
logger.info "Message with message_id #{message_id} returned #{basic_return.inspect}"
|
126
|
+
ack_id, = ack_map.each_pair.find {|_, msg_id| msg_id == message_id }
|
127
|
+
|
128
|
+
sended_messages.delete(ack_id)&.reject(args) if ack_map.delete(ack_id)
|
129
|
+
rescue StandardError => e
|
130
|
+
# TODO: возможно стоит попробовать почистить ack_map и sended_messages
|
131
|
+
logger.error "[CRITICAL]: #{e.inspect}.\n#{e.backtrace.first(10).join("\n")}"
|
132
|
+
end
|
133
|
+
|
134
|
+
def on_confirm(channel, ack_id, flag, neg)
|
135
|
+
logger.debug "Call confirmed callback for message with ack_id #{ack_id} with neg=#{neg}"
|
136
|
+
args = { channel: channel, ack_id: ack_id, flag: flag, neg: neg }
|
137
|
+
if ack_map.delete(ack_id) && (f = sended_messages.delete(ack_id)).present?
|
138
|
+
if neg
|
139
|
+
f.reject(args)
|
140
|
+
else
|
141
|
+
f.fulfill(args)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
rescue StandardError => e
|
145
|
+
# TODO: возможно стоит попробовать почистить ack_map и sended_messages
|
146
|
+
logger.error "[CRITICAL]: #{e.inspect}.\n#{e.backtrace.first(10).join("\n")}"
|
147
|
+
end
|
148
|
+
|
149
|
+
# Send amqp message and save meta information for processing
|
150
|
+
# @param exchange [String] exchange name
|
151
|
+
# @param routing_key [String] message routing key
|
152
|
+
# @param payload [Object] message payload. Converted to json calling to_json method
|
153
|
+
# @param options [Hash] amqp message properties
|
154
|
+
# @return [Concurrent::Promises::ResolvableFuture] future for checking success publishing
|
155
|
+
def send_message(exchange, routing_key, payload, options)
|
156
|
+
configure_exchange(exchange)
|
157
|
+
channel.synchronize do
|
158
|
+
ack_id = channel.next_publish_seq_no
|
159
|
+
options[:message_id] ||= SecureRandom.uuid
|
160
|
+
# в случае укаказанного message_id в качестве числа, on_return вернет message_id в качестве строки
|
161
|
+
ack_map[ack_id] = options[:message_id].to_s
|
162
|
+
future = sended_messages[ack_id] = Concurrent::Promises.resolvable_future
|
163
|
+
logger.debug "Publish message #{options[:message_id]} with ack: #{ack_id} to #{exchange}##{routing_key}"
|
164
|
+
data = if payload.is_a?(String)
|
165
|
+
payload
|
166
|
+
else
|
167
|
+
Oj.generate(payload)
|
168
|
+
end
|
169
|
+
channel.basic_publish(data, exchange, routing_key, options)
|
170
|
+
future
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'bunny'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'bbk/amqp/utils'
|
4
|
+
|
5
|
+
module BBK
|
6
|
+
module AMQP
|
7
|
+
module Spec
|
8
|
+
module RabbitHelper
|
9
|
+
|
10
|
+
cattr_accessor :mq_defaults
|
11
|
+
|
12
|
+
def self.prepare_certs(fixtures_path)
|
13
|
+
FileUtils.mkdir_p File.join(fixtures_path, 'keys')
|
14
|
+
|
15
|
+
cert_path = File.join(fixtures_path, 'keys', 'cert.pem')
|
16
|
+
key_path = File.join(fixtures_path, 'keys', 'key.pem')
|
17
|
+
cacert_path = File.join(fixtures_path, 'keys', 'cacert.pem')
|
18
|
+
|
19
|
+
{
|
20
|
+
'TEST_CLIENT_CERT' => cert_path,
|
21
|
+
'TEST_CLIENT_KEY' => key_path,
|
22
|
+
'CA_CERT' => cacert_path
|
23
|
+
}.each_pair do |env, file|
|
24
|
+
File.write(file, ENV[env]) if ENV[env].present?
|
25
|
+
end
|
26
|
+
|
27
|
+
[cert_path, key_path, cacert_path]
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.included(_mod)
|
31
|
+
cert_path, key_path, cacert_path = prepare_certs(File.join($root, 'fixtures'))
|
32
|
+
|
33
|
+
self.mq_defaults = {
|
34
|
+
host: ENV['MQ_HOST'] || 'mq',
|
35
|
+
port: ENV['MQ_PORT'] || 5671,
|
36
|
+
tls: true,
|
37
|
+
tls_cert: cert_path,
|
38
|
+
tls_key: key_path,
|
39
|
+
tls_ca_certificates: [cacert_path],
|
40
|
+
verify_peer: false,
|
41
|
+
verify_ssl: false,
|
42
|
+
verify: false,
|
43
|
+
auth_mechanism: 'EXTERNAL',
|
44
|
+
automatically_recover: false,
|
45
|
+
automatic_recovery: false,
|
46
|
+
recover_from_connection_close: false,
|
47
|
+
continuation_timeout: 10_000,
|
48
|
+
heartbeat: 10
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def commonname
|
53
|
+
BBK::AMQP::Utils.commonname(mq_defaults[:tls_cert])
|
54
|
+
end
|
55
|
+
|
56
|
+
def mq_connection(options = {})
|
57
|
+
Bunny.new(mq_defaults.merge(options))
|
58
|
+
end
|
59
|
+
|
60
|
+
def mq_pop(queue, timeout = 10)
|
61
|
+
BBK::AMQP::Utils.pop queue, timeout
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bunny'
|
4
|
+
require 'openssl'
|
5
|
+
|
6
|
+
module BBK
|
7
|
+
module AMQP
|
8
|
+
module Utils
|
9
|
+
|
10
|
+
# Try get message from amqp queue
|
11
|
+
# @param queue [Bunny::Queue]
|
12
|
+
# @param timeout [Integer] in seconds for waiting message message in queue
|
13
|
+
# @raise [Timeout::Error] if queue empty in timeout time duration
|
14
|
+
# @return [Array] array with delivery_info, metadata and payload
|
15
|
+
def self.pop(queue, timeout = 10)
|
16
|
+
unblocker = Queue.new
|
17
|
+
consumer = queue.subscribe(block: false) do |delivery_info, metadata, payload|
|
18
|
+
message = [
|
19
|
+
delivery_info,
|
20
|
+
metadata.to_hash.with_indifferent_access,
|
21
|
+
begin
|
22
|
+
Oj.load(payload).with_indifferent_access
|
23
|
+
rescue StandardError
|
24
|
+
payload
|
25
|
+
end
|
26
|
+
]
|
27
|
+
unblocker << message
|
28
|
+
end
|
29
|
+
Thread.new do
|
30
|
+
sleep timeout
|
31
|
+
unblocker << :timeout
|
32
|
+
end
|
33
|
+
result = unblocker.pop
|
34
|
+
consumer.cancel
|
35
|
+
raise ::Timeout::Error if result == :timeout
|
36
|
+
|
37
|
+
result
|
38
|
+
end
|
39
|
+
|
40
|
+
# Extract CN certificate attribute from certificate path
|
41
|
+
# @param cert_path [String] path to certificate file
|
42
|
+
# @return [String] certificate CN attribute value
|
43
|
+
def self.commonname(cert_path)
|
44
|
+
cert = OpenSSL::X509::Certificate.new(File.read(cert_path))
|
45
|
+
cert.subject.to_a.find {|name, _, _| name == 'CN' }[1]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Set default options and create non started connection to amqp
|
49
|
+
# @option options [String] :hosts List of Amqp hosts (default MQ_HOST env variable or mq)
|
50
|
+
# @option options [String] :hostname Amqp host (default MQ_HOST env variable or mq)
|
51
|
+
# @option options [Integer] :port Amqp port (default MQ_PORT env variable or 5671 - default tls port)
|
52
|
+
# @option options [String] :vhost Connected amqp virtual host (default MQ_VHOST env variable or /)
|
53
|
+
# @option options [Boolean] :tls Use tls (default true)
|
54
|
+
# @option options [String] :tls_cert Path to certificate file (default config/keys/cert.pem)
|
55
|
+
# @option options [String] :tls_key Path to key file (default config/keys/key.pem)
|
56
|
+
# @option options [Array] :tls_ca_certificates List to ca certificates (default config/keys/cacert.pem)
|
57
|
+
# @option options [String] :verify Verification option server certificate *
|
58
|
+
# @option options [String] :verify_peer Verification option server certificate *
|
59
|
+
# @option options [String] :verify_ssl Verification option server certificate *
|
60
|
+
# @option options [String] :auth_mechanism Amqp authorization mechanism (default EXTERNAL)
|
61
|
+
# @option options [Boolean] :automatically_recover Allow automatic network failure recovery (default false)
|
62
|
+
# @option options [Boolean] :automatic_recovery Alias for automatically_recover (default false)
|
63
|
+
# @option options [Integer] :recovery_attempts Limits the number of connection recovery attempts performed by Bunny (default 0, nil - unlimited)
|
64
|
+
# @option options [Boolean] :recover_from_connection_close (default false)
|
65
|
+
# @return [Bunny::Session] non started amqp connection
|
66
|
+
def self.create_connection(options = {})
|
67
|
+
hosts = [options[:hosts] || options[:host] || options[:hostname]].flatten.select(&:present?).uniq
|
68
|
+
hosts = hosts.map{|h| h.split(/[;|]/) }.flatten.select(&:present?).uniq
|
69
|
+
|
70
|
+
options[:hosts] = if hosts.empty?
|
71
|
+
[ENV.fetch('MQ_HOST', 'mq')].split(/[;|]/).flatten.select(&:present?).uniq
|
72
|
+
else
|
73
|
+
hosts
|
74
|
+
end
|
75
|
+
|
76
|
+
options[:port] ||= ENV['MQ_PORT'] || 5671
|
77
|
+
options[:vhost] ||= ENV['MQ_VHOST'] || '/'
|
78
|
+
user = options[:username] || options[:user] || ENV['MQ_USER']
|
79
|
+
options[:username] = options[:user] = user
|
80
|
+
|
81
|
+
# Передаем пустую строку чтобы bunny не использовал пароль по умолчанию guest
|
82
|
+
pwd = options[:password] || options[:pass] || options[:pwd] || ENV['MQ_PASS'] || ''
|
83
|
+
options[:password] = options[:pass] = options[:pwd] = pwd
|
84
|
+
|
85
|
+
options[:tls] = options.fetch(:tls, true)
|
86
|
+
options[:tls_cert] ||= 'config/keys/cert.pem'
|
87
|
+
options[:tls_key] ||= 'config/keys/key.pem'
|
88
|
+
options[:tls_ca_certificates] ||= ['config/keys/cacert.pem']
|
89
|
+
|
90
|
+
options[:verify] =
|
91
|
+
options.fetch(:verify, options.fetch(:verify_peer, options.fetch(:verify_ssl, nil)))
|
92
|
+
options[:verify] = true if options[:verify]
|
93
|
+
options[:verify_peer] = options[:verify]
|
94
|
+
options[:verify_ssl] = options[:verify]
|
95
|
+
|
96
|
+
options[:auth_mechanism] ||= if options[:tls]
|
97
|
+
'EXTERNAL'
|
98
|
+
else
|
99
|
+
'PLAIN'
|
100
|
+
end
|
101
|
+
|
102
|
+
options[:automatically_recover] ||= false
|
103
|
+
options[:automatic_recovery] ||= false
|
104
|
+
options[:recovery_attempts] ||= 0
|
105
|
+
options[:recover_attempts] = options[:recovery_attempts]
|
106
|
+
options[:recover_from_connection_close] ||= false
|
107
|
+
Bunny.new(options)
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
data/lib/bbk/amqp.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/core_ext'
|
5
|
+
require 'oj'
|
6
|
+
require 'bbk/utils'
|
7
|
+
require 'bbk/amqp/version'
|
8
|
+
require 'bbk/amqp/utils'
|
9
|
+
require 'bbk/amqp/message'
|
10
|
+
require 'bbk/amqp/publisher'
|
11
|
+
require 'bbk/amqp/consumer'
|
12
|
+
require 'bbk/amqp/route_info'
|
13
|
+
require 'bbk/amqp/domains_set'
|
14
|
+
require 'bbk/amqp/domains/exchange'
|
15
|
+
require 'bbk/amqp/domains/by_block'
|
16
|
+
require_relative 'bunny_patch'
|
17
|
+
|
18
|
+
|
19
|
+
module BBK
|
20
|
+
module AMQP
|
21
|
+
|
22
|
+
class << self
|
23
|
+
|
24
|
+
attr_accessor :logger
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
self.logger = ::BBK::Utils::Logger.default
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module BBK
|
2
|
+
module AMQP
|
3
|
+
class Consumer
|
4
|
+
attr_reader connection: untyped
|
5
|
+
attr_reader queue_name: String
|
6
|
+
attr_reader queue: untyped
|
7
|
+
attr_reader options: Hash[String|Symbol, untyped]
|
8
|
+
attr_reader logger: Logger|BBK::Utils::_ProxyObject
|
9
|
+
|
10
|
+
def initialize: (untyped, ?queue_name: String?, **untyped) -> void
|
11
|
+
|
12
|
+
def protocols: () -> Array[String]
|
13
|
+
|
14
|
+
def run: (BBK::App::Dispatcher::MessageStream) -> void
|
15
|
+
|
16
|
+
def ack: (BBK::App::Dispatcher::_IncomingMessage, *untyped, ?answer: BBK::App::Dispatcher::_Message, **untyped) -> void
|
17
|
+
|
18
|
+
def nack: (BBK::App::Dispatcher::_IncomingMessage, *untyped, ?error: untyped, ?requeue: untyped, **untyped) -> void
|
19
|
+
|
20
|
+
def stop: () -> void
|
21
|
+
|
22
|
+
def close: () -> void
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module BBK
|
2
|
+
module AMQP
|
3
|
+
class DomainsSet
|
4
|
+
def initialize: (*BBK::AMQP::Domains::_Domain) -> void
|
5
|
+
|
6
|
+
def []: (String) -> BBK::AMQP::Domains::_Domain?
|
7
|
+
def add: (BBK::AMQP::Domains::_Domain) -> void
|
8
|
+
def each: () ?{(BBK::AMQP::Domains::_Domain) -> void} -> void
|
9
|
+
| -> Enumerator[BBK::AMQP::Domains::_Domain, void]
|
10
|
+
def has?: (String) -> bool
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module BBK
|
2
|
+
module AMQP
|
3
|
+
class Message
|
4
|
+
include BBK::App::Dispatcher::_IncomingMessage
|
5
|
+
# def ack: (*untyped, ?answer: BBK::App::Dispatcher::Result, **untyped) -> void
|
6
|
+
# def nack: (*untyped, ?error: untyped, **untyped) -> void
|
7
|
+
|
8
|
+
def initialize: (BBK::App::Dispatcher::_Consumer, untyped delivery_info, Hash[String|Symbol, untyped] properties, String? body) -> void
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module BBK
|
2
|
+
module AMQP
|
3
|
+
class Publisher
|
4
|
+
|
5
|
+
include BBK::App::Dispatcher::_Publisher
|
6
|
+
# def publish: (BBK::App::Dispatcher::Result) -> untyped
|
7
|
+
|
8
|
+
HEADER_PROP_FIELDS: Array[Symbol]
|
9
|
+
|
10
|
+
attr_reader connection: untyped
|
11
|
+
|
12
|
+
|
13
|
+
def initialize: (untyped connection, untyped domains, ?logger: _Logger) -> void
|
14
|
+
def protocols: ()-> Array[String]
|
15
|
+
|
16
|
+
|
17
|
+
def publish_message: (String routing_key, BBK::App::Dispatcher::_Message message, exchange: String, ?options: Hash[String|Symbol, untyped]) -> untyped
|
18
|
+
|
19
|
+
def raw_publish: (String? routing_key, exchange: String, ?properties: Hash[String|Symbol, untyped], ?headers: Hash[String|Symbol, untyped], ?payload: Hash[String|Symbol, untyped]|String?) -> untyped
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def initialize_callbacks: () -> void
|
24
|
+
def configure_exchange: (String? exchange_name) -> void
|
25
|
+
def client_name: () -> String
|
26
|
+
def on_return: (untyped exchange, untyped basic_return, Hash[String|Symbol, untyped] properties, String? body) -> void
|
27
|
+
def on_confirm: (untyped channel, Integer ack_id, untyped flag, bool neg) -> untyped
|
28
|
+
def send_message: (String exchange, String? routing_key, Hash[untyped, untyped]?|String? payload, Hash[String|Symbol, untyped] options) -> void
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bbk-amqp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0.72904
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Samoylenko Yuri
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-01-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '6.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bbk-utils
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.0.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bunny
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.19.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.19.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: oj
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bbk-app
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.0.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.0.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: bunny-mock
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: byebug
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rake
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rspec_junit_formatter
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rubycritic
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: simplecov
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: simplecov-console
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
description: AMQP interaction classes for BBK stack
|
196
|
+
email:
|
197
|
+
- kinnalru@gmail.com
|
198
|
+
executables: []
|
199
|
+
extensions: []
|
200
|
+
extra_rdoc_files: []
|
201
|
+
files:
|
202
|
+
- Gemfile
|
203
|
+
- Gemfile.lock
|
204
|
+
- README.md
|
205
|
+
- bin/console
|
206
|
+
- bin/setup
|
207
|
+
- lib/bbk/amqp.rb
|
208
|
+
- lib/bbk/amqp/consumer.rb
|
209
|
+
- lib/bbk/amqp/domains/by_block.rb
|
210
|
+
- lib/bbk/amqp/domains/exchange.rb
|
211
|
+
- lib/bbk/amqp/domains_set.rb
|
212
|
+
- lib/bbk/amqp/message.rb
|
213
|
+
- lib/bbk/amqp/publisher.rb
|
214
|
+
- lib/bbk/amqp/route_info.rb
|
215
|
+
- lib/bbk/amqp/spec.rb
|
216
|
+
- lib/bbk/amqp/spec/rabbit_helper.rb
|
217
|
+
- lib/bbk/amqp/utils.rb
|
218
|
+
- lib/bbk/amqp/version.rb
|
219
|
+
- lib/bbk/bunny_patch.rb
|
220
|
+
- sig/bbk/amqp/consumer.rbs
|
221
|
+
- sig/bbk/amqp/domains/by_block.rbs
|
222
|
+
- sig/bbk/amqp/domains/common.rbs
|
223
|
+
- sig/bbk/amqp/domains/exchange.rbs
|
224
|
+
- sig/bbk/amqp/domains_set.rbs
|
225
|
+
- sig/bbk/amqp/message.rbs
|
226
|
+
- sig/bbk/amqp/publisher.rbs
|
227
|
+
- sig/bbk/amqp/route_info.rbs
|
228
|
+
- sig/bbk/amqp/utils.rbs
|
229
|
+
homepage:
|
230
|
+
licenses: []
|
231
|
+
metadata: {}
|
232
|
+
post_install_message:
|
233
|
+
rdoc_options: []
|
234
|
+
require_paths:
|
235
|
+
- lib
|
236
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
237
|
+
requirements:
|
238
|
+
- - ">="
|
239
|
+
- !ruby/object:Gem::Version
|
240
|
+
version: '0'
|
241
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
242
|
+
requirements:
|
243
|
+
- - ">="
|
244
|
+
- !ruby/object:Gem::Version
|
245
|
+
version: '0'
|
246
|
+
requirements: []
|
247
|
+
rubygems_version: 3.2.32
|
248
|
+
signing_key:
|
249
|
+
specification_version: 4
|
250
|
+
summary: AMQP interaction classes for BBK stack
|
251
|
+
test_files: []
|