amqp 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. data/.gitignore +3 -2
  2. data/CHANGELOG +25 -0
  3. data/Gemfile +4 -2
  4. data/README.md +2 -0
  5. data/{amqp.todo → TODO} +1 -3
  6. data/amqp.gemspec +3 -3
  7. data/bin/irb +2 -2
  8. data/bin/jenkins.sh +25 -0
  9. data/bin/set_test_suite_realms_up.sh +21 -0
  10. data/doc/EXAMPLE_01_PINGPONG +1 -1
  11. data/doc/EXAMPLE_02_CLOCK +1 -1
  12. data/doc/EXAMPLE_03_STOCKS +1 -1
  13. data/doc/EXAMPLE_04_MULTICLOCK +1 -1
  14. data/doc/EXAMPLE_05_ACK +1 -1
  15. data/doc/EXAMPLE_05_POP +1 -1
  16. data/doc/EXAMPLE_06_HASHTABLE +1 -1
  17. data/examples/{mq/ack.rb → ack.rb} +6 -6
  18. data/examples/{mq/automatic_binding_for_default_direct_exchange.rb → automatic_binding_for_default_direct_exchange.rb} +4 -4
  19. data/examples/{mq/callbacks.rb → callbacks.rb} +2 -2
  20. data/examples/{mq/clock.rb → clock.rb} +5 -5
  21. data/examples/{mq/hashtable.rb → hashtable.rb} +4 -4
  22. data/examples/{mq/internal.rb → internal.rb} +5 -5
  23. data/examples/{mq/logger.rb → logger.rb} +5 -5
  24. data/examples/{mq/multiclock.rb → multiclock.rb} +4 -4
  25. data/examples/{mq/pingpong.rb → pingpong.rb} +5 -5
  26. data/examples/{mq/pop.rb → pop.rb} +3 -3
  27. data/examples/{mq/primes-simple.rb → primes-simple.rb} +0 -0
  28. data/examples/{mq/primes.rb → primes.rb} +6 -6
  29. data/examples/{amqp/simple.rb → simple.rb} +1 -1
  30. data/examples/{mq/stocks.rb → stocks.rb} +5 -5
  31. data/lib/amqp.rb +8 -112
  32. data/lib/amqp/basic_client.rb +58 -0
  33. data/lib/amqp/channel.rb +937 -0
  34. data/lib/amqp/client.rb +72 -79
  35. data/lib/{mq → amqp}/collection.rb +12 -2
  36. data/lib/amqp/connection.rb +115 -0
  37. data/lib/amqp/exceptions.rb +18 -0
  38. data/lib/{mq → amqp}/exchange.rb +32 -34
  39. data/lib/{ext → amqp/ext}/em.rb +1 -1
  40. data/lib/{ext → amqp/ext}/emfork.rb +0 -0
  41. data/lib/amqp/frame.rb +3 -3
  42. data/lib/{mq → amqp}/header.rb +5 -11
  43. data/lib/{mq → amqp}/logger.rb +2 -2
  44. data/lib/amqp/protocol.rb +2 -2
  45. data/lib/{mq → amqp}/queue.rb +20 -17
  46. data/lib/{mq → amqp}/rpc.rb +20 -8
  47. data/lib/amqp/server.rb +1 -1
  48. data/lib/amqp/version.rb +1 -1
  49. data/lib/mq.rb +20 -964
  50. data/protocol/codegen.rb +1 -1
  51. data/research/api.rb +3 -3
  52. data/research/primes-forked.rb +5 -5
  53. data/research/primes-processes.rb +5 -5
  54. data/research/primes-threaded.rb +5 -5
  55. data/spec/integration/authentication_spec.rb +114 -0
  56. data/spec/integration/automatic_binding_for_default_direct_exchange_spec.rb +13 -12
  57. data/spec/{unit/mq → integration}/channel_close_spec.rb +2 -2
  58. data/spec/{unit/mq → integration}/exchange_declaration_spec.rb +26 -14
  59. data/spec/{unit/mq → integration}/queue_declaration_spec.rb +4 -4
  60. data/spec/integration/queue_exclusivity_spec.rb +95 -0
  61. data/spec/integration/reply_queue_communication_spec.rb +63 -0
  62. data/spec/integration/store_and_forward_spec.rb +121 -0
  63. data/spec/integration/topic_subscription_spec.rb +193 -0
  64. data/spec/integration/workload_distribution_spec.rb +245 -0
  65. data/spec/spec_helper.rb +16 -32
  66. data/spec/unit/{mq/mq_basic_spec.rb → amqp/basic_spec.rb} +4 -4
  67. data/spec/unit/{mq → amqp}/collection_spec.rb +22 -7
  68. data/spec/unit/amqp/connection_spec.rb +116 -0
  69. data/spec/unit/amqp/frame_spec.rb +18 -18
  70. data/spec/unit/amqp/protocol_spec.rb +9 -11
  71. metadata +54 -49
  72. data/lib/ext/blankslate.rb +0 -9
  73. data/spec/mq_helper.rb +0 -70
  74. data/spec/unit/amqp/client_spec.rb +0 -472
  75. data/spec/unit/amqp/misc_spec.rb +0 -123
  76. data/spec/unit/mq/misc_spec.rb +0 -228
  77. data/spec/unit/mq/queue_spec.rb +0 -71
@@ -1,60 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
- require File.expand_path('../frame', __FILE__)
3
+ require "amqp/basic_client"
4
4
 
5
5
  require 'uri'
6
6
 
7
7
  module AMQP
8
- class Error < StandardError; end
9
-
10
- module BasicClient
11
- attr_reader :broker
12
-
13
- def process_frame(frame)
14
- if mq = channels[frame.channel]
15
- mq.process_frame(frame)
16
- return
17
- end
18
-
19
- case frame
20
- when Frame::Method
21
- case method = frame.payload
22
- when Protocol::Connection::Start
23
- @broker = method
24
- send Protocol::Connection::StartOk.new({:platform => 'Ruby/EventMachine',
25
- :product => 'AMQP',
26
- :information => 'http://github.com/ruby-amqp/amqp',
27
- :version => VERSION},
28
- 'AMQPLAIN',
29
- {:LOGIN => @settings[:user],
30
- :PASSWORD => @settings[:pass]},
31
- 'en_US')
32
-
33
- when Protocol::Connection::Tune
34
- send Protocol::Connection::TuneOk.new(:channel_max => 0,
35
- :frame_max => 131072,
36
- :heartbeat => 0)
37
-
38
- send Protocol::Connection::Open.new(:virtual_host => @settings[:vhost],
39
- :capabilities => '',
40
- :insist => @settings[:insist])
41
-
42
- @on_disconnect = method(:disconnected)
43
-
44
- when Protocol::Connection::OpenOk
45
- succeed(self)
46
-
47
- when Protocol::Connection::Close
48
- # raise Error, "#{method.reply_text} in #{Protocol.classes[method.class_id].methods[method.method_id]}"
49
- STDERR.puts "#{method.reply_text} in #{Protocol.classes[method.class_id].methods[method.method_id]}"
50
-
51
- when Protocol::Connection::CloseOk
52
- @on_disconnect.call if @on_disconnect
53
- end
54
- end
55
- end
56
- end
57
-
58
8
  def self.client
59
9
  @client ||= BasicClient
60
10
  end
@@ -78,25 +28,55 @@ module AMQP
78
28
  timeout @settings[:timeout] if @settings[:timeout]
79
29
  errback { @on_disconnect.call } unless @reconnecting
80
30
 
81
- @connected = false
31
+ # TCP connection "openness"
32
+ @tcp_connection_established = false
33
+ # AMQP connection "openness"
34
+ @connected = false
82
35
  end
83
36
 
84
37
  def connection_completed
85
- start_tls if @settings[:ssl]
38
+ if @settings[:ssl].is_a? Hash
39
+ start_tls @settings[:ssl]
40
+ elsif @settings[:ssl]
41
+ start_tls
42
+ end
43
+
86
44
  log 'connected'
87
45
  # @on_disconnect = proc { raise Error, 'Disconnected from server' }
88
46
  unless @closing
89
47
  @reconnecting = false
90
48
  end
91
49
 
92
- @connected = true
93
- @connection_status.call(:connected) if @connection_status
50
+ @tcp_connection_established = true
94
51
 
95
52
  @buf = Buffer.new
96
53
  send_data HEADER
97
54
  send_data [1, 1, VERSION_MAJOR, VERSION_MINOR].pack('C4')
55
+
56
+ if heartbeat = @settings[:heartbeat]
57
+ init_heartbeat if (@settings[:heartbeat] = heartbeat.to_i) > 0
58
+ end
98
59
  end
99
60
 
61
+ def init_heartbeat
62
+ @last_server_heartbeat = Time.now
63
+
64
+ @timer ||= EM::PeriodicTimer.new(@settings[:heartbeat]) do
65
+ if connected?
66
+ if @last_server_heartbeat < (Time.now - (@settings[:heartbeat] * 2))
67
+ log "Reconnecting due to missing server heartbeats"
68
+ reconnect(true)
69
+ else
70
+ send AMQP::Frame::Heartbeat.new
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ def tcp_connection_established?
77
+ @tcp_connection_established
78
+ end # tcp_connection_established?
79
+
100
80
  def connected?
101
81
  @connected
102
82
  end
@@ -104,7 +84,7 @@ module AMQP
104
84
  def unbind
105
85
  log 'disconnected'
106
86
  @connected = false
107
- EM.next_tick { @on_disconnect.call }
87
+ EM.next_tick { @on_disconnect.call; @tcp_connection_established = false }
108
88
  end
109
89
 
110
90
  def add_channel(mq)
@@ -198,17 +178,27 @@ module AMQP
198
178
  EM.reconnect @settings[:host], @settings[:port], self
199
179
  end
200
180
 
201
- def self.connect amqp_url_or_opts = nil
202
- if amqp_url_or_opts.is_a?(String)
203
- opts = parse_amqp_url(amqp_url_or_opts)
204
- elsif amqp_url_or_opts.is_a?(Hash)
205
- opts = amqp_url_or_opts
206
- elsif amqp_url_or_opts.nil?
207
- opts = Hash.new
181
+ def self.connect(arg = nil)
182
+ opts = case arg
183
+ when String then
184
+ opts = parse_connection_uri(arg)
185
+ when Hash then
186
+ arg
187
+ else
188
+ Hash.new
189
+ end
190
+
191
+ options = AMQP.settings.merge(opts)
192
+
193
+ if options[:username]
194
+ options[:user] = options.delete(:username)
208
195
  end
209
196
 
210
- opts = AMQP.settings.merge(opts)
211
- EM.connect opts[:host], opts[:port], self, opts
197
+ if options[:password]
198
+ options[:pass] = options.delete(:password)
199
+ end
200
+
201
+ EM.connect options[:host], options[:port], self, options
212
202
  end
213
203
 
214
204
  def connection_status(&blk)
@@ -217,6 +207,23 @@ module AMQP
217
207
 
218
208
  private
219
209
 
210
+ def self.parse_connection_uri(connection_string)
211
+ uri = URI.parse(connection_string)
212
+ raise("amqp:// uri required!") unless %w{amqp amqps}.include?(uri.scheme)
213
+
214
+ opts = {}
215
+
216
+ opts[:user] = URI.unescape(uri.user) if uri.user
217
+ opts[:pass] = URI.unescape(uri.password) if uri.password
218
+ opts[:vhost] = URI.unescape(uri.path) if uri.path
219
+ opts[:host] = uri.host if uri.host
220
+ opts[:port] = uri.port || Hash["amqp" => 5672, "amqps" => 5671][uri.scheme]
221
+ opts[:ssl] = uri.scheme == "amqps"
222
+
223
+ opts
224
+ end
225
+
226
+
220
227
  def disconnected
221
228
  @connection_status.call(:disconnected) if @connection_status
222
229
  reconnect
@@ -228,19 +235,5 @@ module AMQP
228
235
  pp args
229
236
  puts
230
237
  end
231
-
232
- def self.parse_amqp_url(amqp_url)
233
- uri = URI.parse(amqp_url)
234
- raise("amqp:// uri required!") unless %w{amqp amqps}.include? uri.scheme
235
- opts = {}
236
- opts[:user] = URI.unescape(uri.user) if uri.user
237
- opts[:pass] = URI.unescape(uri.password) if uri.password
238
- opts[:vhost] = URI.unescape(uri.path) if uri.path
239
- opts[:host] = uri.host if uri.host
240
- opts[:port] = uri.port ? uri.port :
241
- {"amqp" => 5672, "amqps" => 5671}[uri.scheme]
242
- opts[:ssl] = uri.scheme == "amqps"
243
- return opts
244
- end
245
238
  end
246
239
  end
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
- class MQ
4
- # MQ::Collection is used to store named AMQ model entities (exchanges, queues)
3
+ module AMQP
4
+ # AMQP::Collection is used to store named AMQ model entities (exchanges, queues)
5
5
  class Collection < ::Array
6
6
  class IncompatibleItemError < ArgumentError
7
7
  def initialize(item)
@@ -46,5 +46,15 @@ class MQ
46
46
  __push__(item)
47
47
  return item
48
48
  end
49
+
50
+ def include?(name)
51
+ not self[name].nil?
52
+ end
53
+
54
+ def delete(name)
55
+ if self.include?(name)
56
+ self.delete_at(self.index(self[name]))
57
+ end
58
+ end
49
59
  end
50
60
  end
@@ -0,0 +1,115 @@
1
+ # encoding: utf-8
2
+
3
+ require "amqp/ext/em"
4
+
5
+ require "amqp/buffer"
6
+ require "amqp/spec"
7
+ require "amqp/protocol"
8
+ require "amqp/frame"
9
+ require "amqp/client"
10
+
11
+ module AMQP
12
+ class << self
13
+ @logging = false
14
+ attr_accessor :logging
15
+ attr_reader :conn, :closing
16
+ alias :closing? :closing
17
+ alias :connection :conn
18
+ end
19
+
20
+ def self.connect *args
21
+ Client.connect *args
22
+ end
23
+
24
+ def self.settings
25
+ @settings ||= {
26
+ # server address
27
+ :host => '127.0.0.1',
28
+ :port => PORT,
29
+
30
+ # login details
31
+ :user => 'guest',
32
+ :pass => 'guest',
33
+ :vhost => '/',
34
+
35
+ # connection timeout
36
+ :timeout => nil,
37
+
38
+ # logging
39
+ :logging => false,
40
+
41
+ # ssl
42
+ :ssl => false
43
+ }
44
+ end
45
+
46
+ # Must be called to startup the connection to the AMQP server.
47
+ #
48
+ # The method takes several arguments and an optional block.
49
+ #
50
+ # This takes any option that is also accepted by EventMachine::connect.
51
+ # Additionally, there are several AMQP-specific options.
52
+ #
53
+ # * :user => String (default 'guest')
54
+ # The username as defined by the AMQP server.
55
+ # * :pass => String (default 'guest')
56
+ # The password for the associated :user as defined by the AMQP server.
57
+ # * :vhost => String (default '/')
58
+ # The virtual host as defined by the AMQP server.
59
+ # * :timeout => Numeric (default nil)
60
+ # Measured in seconds.
61
+ # * :logging => true | false (default false)
62
+ # Toggle the extremely verbose logging of all protocol communications
63
+ # between the client and the server. Extremely useful for debugging.
64
+ #
65
+ # AMQP.start do
66
+ # # default is to connect to localhost:5672
67
+ #
68
+ # # define queues, exchanges and bindings here.
69
+ # # also define all subscriptions and/or publishers
70
+ # # here.
71
+ #
72
+ # # this block never exits unless EM.stop_event_loop
73
+ # # is called.
74
+ # end
75
+ #
76
+ # Most code will use the MQ api. Any calls to AMQP::Channel.direct / AMQP::Channel.fanout /
77
+ # AMQP::Channel.topic / AMQP::Channel.queue will implicitly call #start. In those cases,
78
+ # it is sufficient to put your code inside of an EventMachine.run
79
+ # block. See the code examples in AMQP for details.
80
+ #
81
+ def self.start *args, &blk
82
+ EM.run {
83
+ @conn ||= connect *args
84
+ @conn.callback(&blk) if blk
85
+ @conn
86
+ }
87
+ end
88
+
89
+ class << self
90
+ alias :run :start
91
+ end
92
+
93
+ def self.stop
94
+ if @conn and not @closing
95
+ @closing = true
96
+ EM.next_tick do
97
+ @conn.close {
98
+ yield if block_given?
99
+ @conn = nil
100
+ @closing = false
101
+ }
102
+ end
103
+ end
104
+ end
105
+
106
+ def self.fork workers
107
+ EM.fork(workers) do
108
+ # clean up globals in the fork
109
+ Thread.current[:mq] = nil
110
+ AMQP.instance_variable_set('@conn', nil)
111
+
112
+ yield
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ module AMQP
4
+ # Raised whenever an illegal operation is attempted.
5
+ class Error < StandardError; end
6
+
7
+ class IncompatibleOptionsError < Error
8
+ def initialize(name, opts_1, opts_2)
9
+ super("There is already an instance called #{name} with options #{opts_1.inspect}, you can't define the same instance with different options (#{opts_2.inspect})!")
10
+ end
11
+ end # IncompatibleOptionsError
12
+
13
+ class ChannelClosedError < Error
14
+ def initialize(instance)
15
+ super("The channel #{instance.channel} was closed, you can't use it anymore!")
16
+ end
17
+ end # ChannelClosedError
18
+ end # AMQP
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- class MQ
3
+ module AMQP
4
4
  # An Exchange acts as an ingress point for all published messages. An
5
5
  # exchange may also be described as a router or a matcher. Every
6
6
  # published message is received by an exchange which, depending on its
@@ -14,7 +14,7 @@ class MQ
14
14
  # As part of the standard, the server _must_ predeclare the direct exchange
15
15
  # 'amq.direct' and the fanout exchange 'amq.fanout' (all exchange names
16
16
  # starting with 'amq.' are reserved). Attempts to declare an exchange using
17
- # 'amq.' as the name will raise an MQ:Error and fail. In practice these
17
+ # 'amq.' as the name will raise an AMQP::Error and fail. In practice these
18
18
  # default exchanges are never used directly by client code.
19
19
  #
20
20
  # These predececlared exchanges are used when the client code declares
@@ -23,14 +23,6 @@ class MQ
23
23
  #
24
24
  class Exchange
25
25
 
26
- #
27
- # Behaviors
28
- #
29
-
30
- include AMQP
31
-
32
-
33
-
34
26
  #
35
27
  # API
36
28
  #
@@ -45,12 +37,12 @@ class MQ
45
37
  # predefined in the system, so you can use it straightaway.
46
38
 
47
39
  # Example:
48
- # MQ.new.queue("tasks")
49
- # MQ::Exchange.default.publish("make clean", routing_key: "tasks")
40
+ # AMQP::Channel.new.queue("tasks")
41
+ # AMQP::Channel::Exchange.default.publish("make clean", routing_key: "tasks")
50
42
 
51
43
  # For more info see section 2.1.2.4 Automatic Mode of the AMQP 0.9.1 spec.
52
- def self.default
53
- @@default ||= self.new(MQ.new, :direct, "", :no_declare => true)
44
+ def self.default(channel = nil)
45
+ self.new(channel || AMQP::Channel.new, :direct, "", :no_declare => true)
54
46
  end
55
47
 
56
48
  def self.add_default_options(type, name, opts, block)
@@ -65,7 +57,7 @@ class MQ
65
57
  # As part of the standard, the server _must_ predeclare the direct exchange
66
58
  # 'amq.direct' and the fanout exchange 'amq.fanout' (all exchange names
67
59
  # starting with 'amq.' are reserved). Attempts to declare an exchange using
68
- # 'amq.' as the name will raise an MQ:Error and fail. In practice these
60
+ # 'amq.' as the name will raise an AMQP::Error and fail. In practice these
69
61
  # default exchanges are never used directly by client code.
70
62
  #
71
63
  # == Direct
@@ -80,14 +72,14 @@ class MQ
80
72
  # called 'amq.direct'. In this case it needs to use :key to do its matching.
81
73
  #
82
74
  # # exchange is named 'foo'
83
- # exchange = MQ::Exchange.new(MQ.new, :direct, 'foo')
75
+ # exchange = AMQP::Channel::Exchange.new(AMQP::Channel.new, :direct, 'foo')
84
76
  #
85
77
  # # or, the exchange can use the default name (amq.direct) and perform
86
78
  # # routing comparisons using the :key
87
- # exchange = MQ::Exchange.new(MQ.new, :direct, "", :key => 'foo')
79
+ # exchange = AMQP::Channel::Exchange.new(AMQP::Channel.new, :direct, "", :key => 'foo')
88
80
  # exchange.publish('some data') # will be delivered to queue bound to 'foo'
89
81
  #
90
- # queue = MQ::Queue.new(MQ.new, 'foo')
82
+ # queue = AMQP::Channel::Queue.new(AMQP::Channel.new, 'foo')
91
83
  # # can receive data since the queue name and the exchange key match exactly
92
84
  # queue.pop { |data| puts "received data [#{data}]" }
93
85
  #
@@ -105,21 +97,21 @@ class MQ
105
97
  # In this case it needs to use :key to do its matching.
106
98
  #
107
99
  # EM.run do
108
- # clock = MQ::Exchange.new(MQ.new, :fanout, 'clock')
100
+ # clock = AMQP::Channel::Exchange.new(AMQP::Channel.new, :fanout, 'clock')
109
101
  # EM.add_periodic_timer(1) do
110
102
  # puts "\npublishing #{time = Time.now}"
111
103
  # clock.publish(Marshal.dump(time))
112
104
  # end
113
105
  #
114
106
  # # one way of defining a queue
115
- # amq = MQ::Queue.new(MQ.new, 'every second')
116
- # amq.bind(MQ.fanout('clock')).subscribe do |time|
107
+ # amq = AMQP::Channel::Queue.new(AMQP::Channel.new, 'every second')
108
+ # amq.bind(AMQP::Channel.fanout('clock')).subscribe do |time|
117
109
  # puts "every second received #{Marshal.load(time)}"
118
110
  # end
119
111
  #
120
112
  # # defining a queue using the convenience method
121
113
  # # note the string passed to #bind
122
- # MQ.queue('every 5 seconds').bind('clock').subscribe do |time|
114
+ # AMQP::Channel.queue('every 5 seconds').bind('clock').subscribe do |time|
123
115
  # time = Marshal.load(time)
124
116
  # puts "every 5 seconds received #{time}" if time.strftime('%S').to_i%5 == 0
125
117
  # end
@@ -150,7 +142,7 @@ class MQ
150
142
  # for matching against the published routing key.
151
143
  #
152
144
  # EM.run do
153
- # exch = MQ::Exchange.new(MQ.new, :topic, "stocks")
145
+ # exch = AMQP::Channel::Exchange.new(AMQP::Channel.new, :topic, "stocks")
154
146
  # keys = ['stock.us.aapl', 'stock.de.dax']
155
147
  #
156
148
  # EM.add_periodic_timer(1) do # every second
@@ -159,17 +151,17 @@ class MQ
159
151
  # end
160
152
  #
161
153
  # # match against one dot-separated item
162
- # MQ.queue('us stocks').bind(exch, :key => 'stock.us.*').subscribe do |price|
154
+ # AMQP::Channel.queue('us stocks').bind(exch, :key => 'stock.us.*').subscribe do |price|
163
155
  # puts "us stock price [#{price}]"
164
156
  # end
165
157
  #
166
158
  # # match against multiple dot-separated items
167
- # MQ.queue('all stocks').bind(exch, :key => 'stock.#').subscribe do |price|
159
+ # AMQP::Channel.queue('all stocks').bind(exch, :key => 'stock.#').subscribe do |price|
168
160
  # puts "all stocks: price [#{price}]"
169
161
  # end
170
162
  #
171
163
  # # require exact match
172
- # MQ.queue('only dax').bind(exch, :key => 'stock.de.dax').subscribe do |price|
164
+ # AMQP::Channel.queue('only dax').bind(exch, :key => 'stock.de.dax').subscribe do |price|
173
165
  # puts "dax price [#{price}]"
174
166
  # end
175
167
  # end
@@ -230,8 +222,8 @@ class MQ
230
222
  #
231
223
  # == Exceptions
232
224
  # Doing any of these activities are illegal and will raise exceptions:
233
- #
234
- # * redeclare an already-declared exchange to a different type (raises MQ::IncompatibleOptionsError)
225
+ #
226
+ # * redeclare an already-declared exchange to a different type (raises AMQP::Channel::IncompatibleOptionsError)
235
227
  # * :passive => true and the exchange does not exist (NOT_FOUND)
236
228
  #
237
229
  def initialize(mq, type, name, opts = {}, &block)
@@ -270,12 +262,16 @@ class MQ
270
262
  attr_reader :name, :type, :key, :status
271
263
  attr_accessor :opts, :callback
272
264
 
265
+ def channel
266
+ @mq
267
+ end # channel
268
+
273
269
  # This method publishes a staged file message to a specific exchange.
274
270
  # The file message will be routed to queues as defined by the exchange
275
271
  # configuration and distributed to any active consumers when the
276
272
  # transaction, if any, is committed.
277
273
  #
278
- # exchange = MQ.direct('name', :key => 'foo.bar')
274
+ # exchange = AMQP::Channel.direct('name', :key => 'foo.bar')
279
275
  # exchange.publish("some data")
280
276
  #
281
277
  # The method takes several hash key options which modify the behavior or
@@ -310,6 +306,8 @@ class MQ
310
306
  # message stays in memory and is never persisted to non-volatile (slow)
311
307
  # storage.
312
308
  #
309
+ # * :content_type
310
+ # Content type you want to send the message with. It defaults to "application/octet-stream".
313
311
  def publish(data, opts = {})
314
312
  @mq.callback {
315
313
  out = []
@@ -320,7 +318,7 @@ class MQ
320
318
  data = data.to_s
321
319
 
322
320
  out << Protocol::Header.new(Protocol::Basic,
323
- data.bytesize, { :content_type => 'application/octet-stream',
321
+ data.bytesize, { opts[:content_type] || :content_type => "application/octet-stream",
324
322
  :delivery_mode => (opts[:persistent] ? 2 : 1),
325
323
  :priority => 0 }.merge(opts))
326
324
 
@@ -335,9 +333,9 @@ class MQ
335
333
  # bindings on the exchange are cancelled.
336
334
  #
337
335
  # Further attempts to publish messages to a deleted exchange will raise
338
- # an MQ::Error due to a channel close exception.
336
+ # an AMQP::Channel::Error due to a channel close exception.
339
337
  #
340
- # exchange = MQ.direct('name', :key => 'foo.bar')
338
+ # exchange = AMQP::Channel.direct('name', :key => 'foo.bar')
341
339
  # exchange.delete
342
340
  #
343
341
  # == Options
@@ -351,7 +349,7 @@ class MQ
351
349
  # * :if_unused => true | false (default false)
352
350
  # If set, the server will only delete the exchange if it has no queue
353
351
  # bindings. If the exchange has queue bindings the server does not
354
- # delete it but raises a channel exception instead (MQ:Error).
352
+ # delete it but raises a channel exception instead (AMQP::Error).
355
353
  #
356
354
  def delete(opts = {})
357
355
  @mq.callback {
@@ -392,4 +390,4 @@ class MQ
392
390
  self.callback && self.callback.call(self)
393
391
  end # receive_response
394
392
  end # Exchange
395
- end # MQ
393
+ end # AMQP