bunny 0.8.0 → 0.9.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -1
- data/.travis.yml +14 -4
- data/ChangeLog.md +72 -0
- data/Gemfile +17 -11
- data/README.md +82 -0
- data/bunny.gemspec +6 -13
- data/examples/connection/heartbeat.rb +17 -0
- data/lib/bunny.rb +40 -56
- data/lib/bunny/channel.rb +615 -19
- data/lib/bunny/channel_id_allocator.rb +59 -0
- data/lib/bunny/compatibility.rb +24 -0
- data/lib/bunny/concurrent/condition.rb +63 -0
- data/lib/bunny/consumer.rb +42 -26
- data/lib/bunny/consumer_tag_generator.rb +22 -0
- data/lib/bunny/consumer_work_pool.rb +67 -0
- data/lib/bunny/exceptions.rb +128 -0
- data/lib/bunny/exchange.rb +131 -136
- data/lib/bunny/framing.rb +53 -0
- data/lib/bunny/heartbeat_sender.rb +59 -0
- data/lib/bunny/main_loop.rb +70 -0
- data/lib/bunny/message_metadata.rb +126 -0
- data/lib/bunny/queue.rb +102 -275
- data/lib/bunny/session.rb +478 -0
- data/lib/bunny/socket.rb +44 -0
- data/lib/bunny/system_timer.rb +9 -9
- data/lib/bunny/transport.rb +179 -0
- data/lib/bunny/version.rb +1 -1
- data/spec/compatibility/queue_declare_spec.rb +40 -0
- data/spec/higher_level_api/integration/basic_ack_spec.rb +54 -0
- data/spec/higher_level_api/integration/basic_consume_spec.rb +51 -0
- data/spec/higher_level_api/integration/basic_get_spec.rb +47 -0
- data/spec/higher_level_api/integration/basic_nack_spec.rb +39 -0
- data/spec/higher_level_api/integration/basic_publish_spec.rb +105 -0
- data/spec/higher_level_api/integration/basic_qos_spec.rb +32 -0
- data/spec/higher_level_api/integration/basic_recover_spec.rb +18 -0
- data/spec/higher_level_api/integration/basic_reject_spec.rb +53 -0
- data/spec/higher_level_api/integration/basic_return_spec.rb +33 -0
- data/spec/higher_level_api/integration/channel_close_spec.rb +29 -0
- data/spec/higher_level_api/integration/channel_flow_spec.rb +24 -0
- data/spec/higher_level_api/integration/channel_open_spec.rb +57 -0
- data/spec/higher_level_api/integration/channel_open_stress_spec.rb +22 -0
- data/spec/higher_level_api/integration/confirm_select_spec.rb +19 -0
- data/spec/higher_level_api/integration/connection_spec.rb +340 -0
- data/spec/higher_level_api/integration/exchange_bind_spec.rb +31 -0
- data/spec/higher_level_api/integration/exchange_declare_spec.rb +183 -0
- data/spec/higher_level_api/integration/exchange_delete_spec.rb +37 -0
- data/spec/higher_level_api/integration/exchange_unbind_spec.rb +40 -0
- data/spec/higher_level_api/integration/queue_bind_spec.rb +109 -0
- data/spec/higher_level_api/integration/queue_declare_spec.rb +129 -0
- data/spec/higher_level_api/integration/queue_delete_spec.rb +38 -0
- data/spec/higher_level_api/integration/queue_purge_spec.rb +30 -0
- data/spec/higher_level_api/integration/queue_unbind_spec.rb +33 -0
- data/spec/higher_level_api/integration/tx_commit_spec.rb +21 -0
- data/spec/higher_level_api/integration/tx_rollback_spec.rb +21 -0
- data/spec/lower_level_api/integration/basic_cancel_spec.rb +57 -0
- data/spec/lower_level_api/integration/basic_consume_spec.rb +100 -0
- data/spec/spec_helper.rb +64 -0
- data/spec/unit/bunny_spec.rb +15 -0
- data/spec/unit/concurrent/condition_spec.rb +66 -0
- metadata +135 -93
- data/CHANGELOG +0 -21
- data/README.textile +0 -76
- data/Rakefile +0 -14
- data/examples/simple.rb +0 -32
- data/examples/simple_ack.rb +0 -35
- data/examples/simple_consumer.rb +0 -55
- data/examples/simple_fanout.rb +0 -41
- data/examples/simple_headers.rb +0 -42
- data/examples/simple_publisher.rb +0 -29
- data/examples/simple_topic.rb +0 -61
- data/ext/amqp-0.9.1.json +0 -389
- data/ext/config.yml +0 -4
- data/ext/qparser.rb +0 -426
- data/lib/bunny/client.rb +0 -370
- data/lib/bunny/subscription.rb +0 -92
- data/lib/qrack/amq-client-url.rb +0 -165
- data/lib/qrack/channel.rb +0 -20
- data/lib/qrack/client.rb +0 -247
- data/lib/qrack/errors.rb +0 -5
- data/lib/qrack/protocol/protocol.rb +0 -135
- data/lib/qrack/protocol/spec.rb +0 -525
- data/lib/qrack/qrack.rb +0 -20
- data/lib/qrack/queue.rb +0 -40
- data/lib/qrack/subscription.rb +0 -152
- data/lib/qrack/transport/buffer.rb +0 -305
- data/lib/qrack/transport/frame.rb +0 -102
- data/spec/spec_09/amqp_url_spec.rb +0 -19
- data/spec/spec_09/bunny_spec.rb +0 -76
- data/spec/spec_09/connection_spec.rb +0 -34
- data/spec/spec_09/exchange_spec.rb +0 -173
- data/spec/spec_09/queue_spec.rb +0 -240
data/lib/bunny/subscription.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Bunny
|
4
|
-
|
5
|
-
# Asks the server to start a "consumer", which is a transient request for messages from a specific
|
6
|
-
# queue. Consumers last as long as the channel they were created on, or until the client cancels them
|
7
|
-
# with an @unsubscribe@. Every time a message reaches the queue it is passed to the @blk@ for
|
8
|
-
# processing. If error occurs, {Bunny::ProtocolError} is raised.
|
9
|
-
#
|
10
|
-
# @option opts [String] :consumer_tag
|
11
|
-
# Specifies the identifier for the consumer. The consumer tag is
|
12
|
-
# local to a connection, so two clients can use the same consumer tags.
|
13
|
-
# If this option is not specified a server generated name is used.
|
14
|
-
#
|
15
|
-
# @option opts [Boolean] :ack (false)
|
16
|
-
# If set to @false@, the server does not expect an acknowledgement message
|
17
|
-
# from the client. If set to @true, the server expects an acknowledgement
|
18
|
-
# message from the client and will re-queue the message if it does not
|
19
|
-
# receive one within a time specified by the server.
|
20
|
-
#
|
21
|
-
# @option opts [Boolean] :exclusive (false)
|
22
|
-
# Request exclusive consumer access, meaning only this consumer can access the queue.
|
23
|
-
#
|
24
|
-
# @option opts [Boolean] :nowait (false)
|
25
|
-
# Ignored by Bunny, always @false@.
|
26
|
-
#
|
27
|
-
# @option opts [Numeric] :timeout
|
28
|
-
# The subscribe loop will continue to wait for messages
|
29
|
-
# until terminated (Ctrl-C or kill command) or this timeout interval is reached.
|
30
|
-
#
|
31
|
-
# @option opts [Integer] :message_max
|
32
|
-
# When the required number of messages is processed subscribe loop is exited.
|
33
|
-
#
|
34
|
-
# @option opts [IO] :cancellator (nil)
|
35
|
-
# A cancellator can be used to for cancelling the subscribe loop from another
|
36
|
-
# thread or from a signal handler. Whenever Bunny notices that this IO object has
|
37
|
-
# become readable, the subscribe loop will be exited after the current message
|
38
|
-
# has been processed.
|
39
|
-
#
|
40
|
-
# h2. Operation
|
41
|
-
#
|
42
|
-
# Passes a hash of message information to the block, if one has been supplied. The hash contains
|
43
|
-
# :header, :payload and :delivery_details. The structure of the data is as follows -
|
44
|
-
#
|
45
|
-
# :header has instance variables -
|
46
|
-
# @klass
|
47
|
-
# @size
|
48
|
-
# @weight
|
49
|
-
# @properties is a hash containing -
|
50
|
-
# :content_type
|
51
|
-
# :delivery_mode
|
52
|
-
# :priority
|
53
|
-
#
|
54
|
-
# :payload contains the message contents
|
55
|
-
#
|
56
|
-
# :delivery details is a hash containing -
|
57
|
-
# :consumer_tag
|
58
|
-
# :delivery_tag
|
59
|
-
# :redelivered
|
60
|
-
# :exchange
|
61
|
-
# :routing_key
|
62
|
-
#
|
63
|
-
# If the :timeout option is specified then the subscription will automatically
|
64
|
-
# cease if the given number of seconds passes with no message arriving.
|
65
|
-
#
|
66
|
-
# @example
|
67
|
-
# my_queue.subscribe(timeout: 5) { |msg| puts msg[:payload] }
|
68
|
-
# my_queue.subscribe(message_max: 10, ack: true) { |msg| puts msg[:payload] }
|
69
|
-
class Subscription < Bunny::Consumer
|
70
|
-
|
71
|
-
def setup_consumer
|
72
|
-
subscription_options = {
|
73
|
-
:deprecated_ticket => 0,
|
74
|
-
:queue => queue.name,
|
75
|
-
:consumer_tag => consumer_tag,
|
76
|
-
:no_ack => !ack,
|
77
|
-
:exclusive => exclusive,
|
78
|
-
:nowait => false
|
79
|
-
}.merge(@opts)
|
80
|
-
|
81
|
-
client.send_frame(Qrack::Protocol::Basic::Consume.new(subscription_options))
|
82
|
-
|
83
|
-
method = client.next_method
|
84
|
-
|
85
|
-
client.check_response(method, Qrack::Protocol::Basic::ConsumeOk, "Error subscribing to queue #{queue.name}, got #{method}")
|
86
|
-
|
87
|
-
@consumer_tag = method.consumer_tag
|
88
|
-
end
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
end
|
data/lib/qrack/amq-client-url.rb
DELETED
@@ -1,165 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
################################################################
|
4
|
-
# DO NOT EDIT THIS FILE ! #
|
5
|
-
# The file comes from https://github.com/ruby-amqp/amq-client, #
|
6
|
-
# it's located in lib/amq/client/settings.rb, so if you want #
|
7
|
-
# to make some changes, please do them in the amq-client repo. #
|
8
|
-
################################################################
|
9
|
-
|
10
|
-
# TODO: When we start to work on porting Bunny on AMQ Client,
|
11
|
-
# this file will become obsolete.
|
12
|
-
|
13
|
-
require "uri"
|
14
|
-
|
15
|
-
module AMQ
|
16
|
-
module Client
|
17
|
-
# @see AMQ::Client::Settings.configure
|
18
|
-
module Settings
|
19
|
-
# @private
|
20
|
-
AMQP_PORTS = {"amqp" => 5672, "amqps" => 5671}.freeze
|
21
|
-
|
22
|
-
# @private
|
23
|
-
AMQPS = "amqps".freeze
|
24
|
-
|
25
|
-
# Default connection settings used by AMQ clients
|
26
|
-
#
|
27
|
-
# @see AMQ::Client::Settings.configure
|
28
|
-
def self.default
|
29
|
-
@default ||= {
|
30
|
-
# server
|
31
|
-
:host => "127.0.0.1",
|
32
|
-
:port => AMQ::Protocol::DEFAULT_PORT,
|
33
|
-
|
34
|
-
# login
|
35
|
-
:user => "guest",
|
36
|
-
:pass => "guest",
|
37
|
-
:vhost => "/",
|
38
|
-
|
39
|
-
# connection timeout
|
40
|
-
:timeout => nil,
|
41
|
-
|
42
|
-
# logging
|
43
|
-
:logging => false,
|
44
|
-
|
45
|
-
# ssl
|
46
|
-
:ssl => false,
|
47
|
-
|
48
|
-
# broker
|
49
|
-
# if you want to load broker-specific extensions
|
50
|
-
:broker => nil,
|
51
|
-
|
52
|
-
:frame_max => 131072
|
53
|
-
}
|
54
|
-
end
|
55
|
-
|
56
|
-
|
57
|
-
def self.client_properties
|
58
|
-
@client_properties ||= {
|
59
|
-
:platform => ::RUBY_DESCRIPTION,
|
60
|
-
:product => "AMQ Client",
|
61
|
-
:information => "http://github.com/ruby-amqp/amq-client",
|
62
|
-
:version => AMQ::Client::VERSION
|
63
|
-
}
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
# Merges given configuration parameters with defaults and returns
|
68
|
-
# the result.
|
69
|
-
#
|
70
|
-
# @param [Hash] Configuration parameters to use.
|
71
|
-
#
|
72
|
-
# @option settings [String] :host ("127.0.0.1") Hostname AMQ broker runs on.
|
73
|
-
# @option settings [String] :port (5672) Port AMQ broker listens on.
|
74
|
-
# @option settings [String] :vhost ("/") Virtual host to use.
|
75
|
-
# @option settings [String] :user ("guest") Username to use for authentication.
|
76
|
-
# @option settings [String] :pass ("guest") Password to use for authentication.
|
77
|
-
# @option settings [String] :ssl (false) Should be use TLS (SSL) for connection?
|
78
|
-
# @option settings [String] :timeout (nil) Connection timeout.
|
79
|
-
# @option settings [String] :logging (false) Turns logging on or off.
|
80
|
-
# @option settings [String] :broker (nil) Broker name (use if you intend to use broker-specific features).
|
81
|
-
# @option settings [Fixnum] :frame_max (131072) Maximum frame size to use. If broker cannot support frames this large, broker's maximum value will be used instead.
|
82
|
-
#
|
83
|
-
# @return [Hash] Merged configuration parameters.
|
84
|
-
def self.configure(settings = nil)
|
85
|
-
case settings
|
86
|
-
when Hash then
|
87
|
-
if username = settings.delete(:username)
|
88
|
-
settings[:user] ||= username
|
89
|
-
end
|
90
|
-
|
91
|
-
if password = settings.delete(:password)
|
92
|
-
settings[:pass] ||= password
|
93
|
-
end
|
94
|
-
|
95
|
-
|
96
|
-
self.default.merge(settings)
|
97
|
-
when String then
|
98
|
-
settings = self.parse_amqp_url(settings)
|
99
|
-
self.default.merge(settings)
|
100
|
-
when NilClass then
|
101
|
-
self.default
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# Parses AMQP connection URI and returns its components as a hash.
|
106
|
-
#
|
107
|
-
# h2. vhost naming schemes
|
108
|
-
#
|
109
|
-
# It is convenient to be able to specify the AMQP connection
|
110
|
-
# parameters as a URI string, and various "amqp" URI schemes
|
111
|
-
# exist. Unfortunately, there is no standard for these URIs, so
|
112
|
-
# while the schemes share the basic idea, they differ in some
|
113
|
-
# details. This implementation aims to encourage URIs that work
|
114
|
-
# as widely as possible.
|
115
|
-
#
|
116
|
-
# The URI scheme should be "amqp", or "amqps" if SSL is required.
|
117
|
-
#
|
118
|
-
# The host, port, username and password are represented in the
|
119
|
-
# authority component of the URI in the same way as in http URIs.
|
120
|
-
#
|
121
|
-
# The vhost is obtained from the first segment of the path, with the
|
122
|
-
# leading slash removed. The path should contain only a single
|
123
|
-
# segment (i.e, the only slash in it should be the leading one).
|
124
|
-
# If the vhost is to include slashes or other reserved URI
|
125
|
-
# characters, these should be percent-escaped.
|
126
|
-
#
|
127
|
-
# @example How vhost is parsed
|
128
|
-
#
|
129
|
-
# AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com") # => vhost is nil, so default (/) will be used
|
130
|
-
# AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/") # => vhost is an empty string
|
131
|
-
# AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/%2Fvault") # => vhost is /vault
|
132
|
-
# AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/production") # => vhost is production
|
133
|
-
# AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/a.b.c") # => vhost is a.b.c
|
134
|
-
# AMQ::Client::Settings.parse_amqp_url("amqp://dev.rabbitmq.com/foo/bar") # => ArgumentError
|
135
|
-
#
|
136
|
-
#
|
137
|
-
# @param [String] connection_string AMQP connection URI, à la JDBC connection string. For example: amqp://bus.megacorp.internal:5877.
|
138
|
-
# @return [Hash] Connection parameters (:username, :password, :vhost, :host, :port, :ssl)
|
139
|
-
#
|
140
|
-
# @raise [ArgumentError] When connection URI schema is not amqp or amqps, or the path contains multiple segments
|
141
|
-
#
|
142
|
-
# @see http://bit.ly/ks8MXK Connecting to The Broker documentation guide
|
143
|
-
# @api public
|
144
|
-
def self.parse_amqp_url(connection_string)
|
145
|
-
uri = URI.parse(connection_string)
|
146
|
-
raise ArgumentError.new("Connection URI must use amqp or amqps schema (example: amqp://bus.megacorp.internal:5766), learn more at http://bit.ly/ks8MXK") unless %w{amqp amqps}.include?(uri.scheme)
|
147
|
-
|
148
|
-
opts = {}
|
149
|
-
|
150
|
-
opts[:scheme] = uri.scheme
|
151
|
-
opts[:user] = URI.unescape(uri.user) if uri.user
|
152
|
-
opts[:pass] = URI.unescape(uri.password) if uri.password
|
153
|
-
opts[:host] = uri.host if uri.host
|
154
|
-
opts[:port] = uri.port || AMQ::Client::Settings::AMQP_PORTS[uri.scheme]
|
155
|
-
opts[:ssl] = uri.scheme == AMQ::Client::Settings::AMQPS
|
156
|
-
if uri.path =~ %r{^/(.*)}
|
157
|
-
raise ArgumentError.new("#{uri} has multiple-segment path; please percent-encode any slashes in the vhost name (e.g. /production => %2Fproduction). Learn more at http://bit.ly/amqp-gem-and-connection-uris") if $1.index('/')
|
158
|
-
opts[:vhost] = URI.unescape($1)
|
159
|
-
end
|
160
|
-
|
161
|
-
opts
|
162
|
-
end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
data/lib/qrack/channel.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Qrack
|
4
|
-
# Channel ancestor class
|
5
|
-
class Channel
|
6
|
-
|
7
|
-
attr_accessor :number, :active, :frame_buffer
|
8
|
-
attr_reader :client
|
9
|
-
|
10
|
-
def initialize(client)
|
11
|
-
@frame_buffer = []
|
12
|
-
@client = client
|
13
|
-
@number = client.channels.size
|
14
|
-
@active = false
|
15
|
-
client.channels[@number] = self
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
data/lib/qrack/client.rb
DELETED
@@ -1,247 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require "qrack/amq-client-url"
|
4
|
-
|
5
|
-
module Qrack
|
6
|
-
|
7
|
-
class ClientTimeout < Timeout::Error; end
|
8
|
-
class ConnectionTimeout < Timeout::Error; end
|
9
|
-
class FrameTimeout < Timeout::Error; end
|
10
|
-
|
11
|
-
# Client ancestor class
|
12
|
-
class Client
|
13
|
-
|
14
|
-
CONNECT_TIMEOUT = 5.0
|
15
|
-
RETRY_DELAY = 10.0
|
16
|
-
|
17
|
-
attr_reader :status, :host, :vhost, :port, :logging, :spec, :heartbeat, :last_method
|
18
|
-
attr_accessor :channel, :logfile, :exchanges, :queues, :channels, :message_in, :message_out, :connecting
|
19
|
-
|
20
|
-
|
21
|
-
def initialize(connection_string_or_opts = Hash.new, opts = Hash.new)
|
22
|
-
opts = case connection_string_or_opts
|
23
|
-
when String then
|
24
|
-
AMQ::Client::Settings.parse_amqp_url(connection_string_or_opts)
|
25
|
-
when Hash then
|
26
|
-
connection_string_or_opts
|
27
|
-
else
|
28
|
-
Hash.new
|
29
|
-
end.merge(opts)
|
30
|
-
|
31
|
-
@host = opts[:host] || 'localhost'
|
32
|
-
@port = opts[:port] || (opts[:ssl] ? Qrack::Protocol::SSL_PORT : Qrack::Protocol::PORT)
|
33
|
-
@user = opts[:user] || 'guest'
|
34
|
-
@pass = opts[:pass] || 'guest'
|
35
|
-
@vhost = opts[:vhost] || '/'
|
36
|
-
@logfile = opts[:logfile] || nil
|
37
|
-
@logging = opts[:logging] || false
|
38
|
-
@ssl = opts[:ssl] || false
|
39
|
-
@ssl_cert = opts[:ssl_cert] || nil
|
40
|
-
@ssl_key = opts[:ssl_key] || nil
|
41
|
-
@ssl_cert_string = opts[:ssl_cert_string] || nil
|
42
|
-
@ssl_key_string = opts[:ssl_key_string] || nil
|
43
|
-
@verify_ssl = opts[:verify_ssl].nil? || opts[:verify_ssl]
|
44
|
-
@status = :not_connected
|
45
|
-
@frame_max = opts[:frame_max] || 131072
|
46
|
-
@channel_max = opts[:channel_max] || 0
|
47
|
-
@heartbeat = opts[:heartbeat] || 0
|
48
|
-
@connect_timeout = opts[:connect_timeout] || CONNECT_TIMEOUT
|
49
|
-
@read_write_timeout = opts[:socket_timeout]
|
50
|
-
@read_write_timeout = nil if @read_write_timeout == 0
|
51
|
-
@disconnect_timeout = @read_write_timeout || @connect_timeout
|
52
|
-
@logger = nil
|
53
|
-
create_logger if @logging
|
54
|
-
@message_in = false
|
55
|
-
@message_out = false
|
56
|
-
@last_method = nil
|
57
|
-
@connecting = false
|
58
|
-
@channels ||= []
|
59
|
-
# Create channel 0
|
60
|
-
@channel = create_channel()
|
61
|
-
@exchanges ||= {}
|
62
|
-
@queues ||= {}
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
# Closes all active communication channels and connection. If an error occurs a @Bunny::ProtocolError@ is raised. If successful, @Client.status@ is set to @:not_connected@.
|
67
|
-
|
68
|
-
# @return [Symbol] @:not_connected@ if successful.
|
69
|
-
def close
|
70
|
-
return if @socket.nil? || @socket.closed?
|
71
|
-
|
72
|
-
# Close all active channels
|
73
|
-
channels.each do |c|
|
74
|
-
Bunny::Timer::timeout(@disconnect_timeout) { c.close } if c.open?
|
75
|
-
end
|
76
|
-
|
77
|
-
# Close connection to AMQP server
|
78
|
-
Bunny::Timer::timeout(@disconnect_timeout) { close_connection }
|
79
|
-
|
80
|
-
rescue Exception
|
81
|
-
# http://cheezburger.com/Asset/View/4033311488
|
82
|
-
ensure
|
83
|
-
# Clear the channels
|
84
|
-
@channels = []
|
85
|
-
|
86
|
-
# Create channel 0
|
87
|
-
@channel = create_channel()
|
88
|
-
|
89
|
-
# Close TCP Socket
|
90
|
-
close_socket
|
91
|
-
end
|
92
|
-
|
93
|
-
alias stop close
|
94
|
-
|
95
|
-
def connected?
|
96
|
-
status == :connected
|
97
|
-
end
|
98
|
-
|
99
|
-
def connecting?
|
100
|
-
connecting
|
101
|
-
end
|
102
|
-
|
103
|
-
def logging=(bool)
|
104
|
-
@logging = bool
|
105
|
-
create_logger if @logging
|
106
|
-
end
|
107
|
-
|
108
|
-
def next_payload(options = {})
|
109
|
-
res = next_frame(options)
|
110
|
-
res.payload if res
|
111
|
-
end
|
112
|
-
|
113
|
-
alias next_method next_payload
|
114
|
-
|
115
|
-
def read(*args)
|
116
|
-
send_command(:read, *args)
|
117
|
-
# Got a SIGINT while waiting; give any traps a chance to run
|
118
|
-
rescue Errno::EINTR
|
119
|
-
retry
|
120
|
-
end
|
121
|
-
|
122
|
-
# Checks to see whether or not an undeliverable message has been returned as a result of a publish
|
123
|
-
# with the <tt>:immediate</tt> or <tt>:mandatory</tt> options.
|
124
|
-
|
125
|
-
# @param [Hash] opts Options.
|
126
|
-
# @option opts [Numeric] :timeout (0.1) The method will wait for a return message until this timeout interval is reached.
|
127
|
-
# @return [Hash] @{:header => nil, :payload => :no_return, :return_details => nil}@ if message is not returned before timeout. @{:header, :return_details, :payload}@ if message is returned. @:return_details@ is a hash @{:reply_code, :reply_text, :exchange, :routing_key}@.
|
128
|
-
def returned_message(opts = {})
|
129
|
-
|
130
|
-
begin
|
131
|
-
frame = next_frame(:timeout => opts[:timeout] || 0.1)
|
132
|
-
rescue Qrack::FrameTimeout
|
133
|
-
return {:header => nil, :payload => :no_return, :return_details => nil}
|
134
|
-
end
|
135
|
-
|
136
|
-
method = frame.payload
|
137
|
-
header = next_payload
|
138
|
-
|
139
|
-
# If maximum frame size is smaller than message payload body then message
|
140
|
-
# will have a message header and several message bodies
|
141
|
-
msg = ''
|
142
|
-
while msg.length < header.size
|
143
|
-
msg << next_payload
|
144
|
-
end
|
145
|
-
|
146
|
-
# Return the message and related info
|
147
|
-
{:header => header, :payload => msg, :return_details => method.arguments}
|
148
|
-
end
|
149
|
-
|
150
|
-
def switch_channel(chann)
|
151
|
-
if (0...channels.size).include? chann
|
152
|
-
@channel = channels[chann]
|
153
|
-
chann
|
154
|
-
else
|
155
|
-
raise RuntimeError, "Invalid channel number - #{chann}"
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
def write(*args)
|
160
|
-
send_command(:write, *args)
|
161
|
-
end
|
162
|
-
|
163
|
-
def read_ready?(timeout, cancelator = nil)
|
164
|
-
io = IO.select([ @socket, cancelator ].compact, nil, nil, timeout)
|
165
|
-
io and io[0].include?(@socket)
|
166
|
-
end
|
167
|
-
|
168
|
-
private
|
169
|
-
|
170
|
-
def close_socket(reason=nil)
|
171
|
-
# Close the socket. The server is not considered dead.
|
172
|
-
@socket.close if @socket and not @socket.closed?
|
173
|
-
@socket = nil
|
174
|
-
@status = :not_connected
|
175
|
-
end
|
176
|
-
|
177
|
-
def create_logger
|
178
|
-
@logfile ? @logger = Logger.new("#{logfile}") : @logger = Logger.new(STDOUT)
|
179
|
-
@logger.level = Logger::INFO
|
180
|
-
@logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
181
|
-
end
|
182
|
-
|
183
|
-
def send_command(cmd, *args)
|
184
|
-
begin
|
185
|
-
raise Bunny::ConnectionError, 'No connection - socket has not been created' if !@socket
|
186
|
-
if @read_write_timeout
|
187
|
-
Bunny::Timer::timeout(@read_write_timeout, Qrack::ClientTimeout) do
|
188
|
-
@socket.__send__(cmd, *args)
|
189
|
-
end
|
190
|
-
else
|
191
|
-
@socket.__send__(cmd, *args)
|
192
|
-
end
|
193
|
-
rescue Errno::EPIPE, Errno::EAGAIN, Qrack::ClientTimeout, IOError => e
|
194
|
-
# Ensure we close the socket when we are down to prevent further
|
195
|
-
# attempts to write to a closed socket
|
196
|
-
close_socket
|
197
|
-
raise Bunny::ServerDownError, e.message
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
def socket
|
202
|
-
return @socket if @socket and (@status == :connected) and not @socket.closed?
|
203
|
-
|
204
|
-
begin
|
205
|
-
# Attempt to connect.
|
206
|
-
@socket = Bunny::Timer::timeout(@connect_timeout, ConnectionTimeout) do
|
207
|
-
TCPSocket.new(host, port)
|
208
|
-
end
|
209
|
-
|
210
|
-
if Socket.constants.include?('TCP_NODELAY') || Socket.constants.include?(:TCP_NODELAY)
|
211
|
-
@socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
|
212
|
-
end
|
213
|
-
|
214
|
-
if @ssl
|
215
|
-
require 'openssl' unless defined? OpenSSL::SSL
|
216
|
-
sslctx = OpenSSL::SSL::SSLContext.new
|
217
|
-
initialize_client_pair(sslctx)
|
218
|
-
@socket = OpenSSL::SSL::SSLSocket.new(@socket, sslctx)
|
219
|
-
@socket.sync_close = true
|
220
|
-
@socket.connect
|
221
|
-
@socket.post_connection_check(host) if @verify_ssl
|
222
|
-
@socket
|
223
|
-
end
|
224
|
-
rescue => e
|
225
|
-
@status = :not_connected
|
226
|
-
raise Bunny::ServerDownError, e.message
|
227
|
-
end
|
228
|
-
|
229
|
-
@socket
|
230
|
-
end
|
231
|
-
|
232
|
-
def initialize_client_pair(sslctx)
|
233
|
-
if @ssl_cert
|
234
|
-
@ssl_cert_string = File.read(@ssl_cert)
|
235
|
-
end
|
236
|
-
if @ssl_key
|
237
|
-
@ssl_key_string = File.read(@ssl_key)
|
238
|
-
end
|
239
|
-
|
240
|
-
sslctx.cert = OpenSSL::X509::Certificate.new(@ssl_cert_string) if @ssl_cert_string
|
241
|
-
sslctx.key = OpenSSL::PKey::RSA.new(@ssl_key_string) if @ssl_key_string
|
242
|
-
sslctx
|
243
|
-
end
|
244
|
-
|
245
|
-
end
|
246
|
-
|
247
|
-
end
|