omf_common 6.0.2.pre.2 → 6.0.2
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.
- data/bin/file_broadcaster.rb +5 -0
- data/bin/file_receiver.rb +5 -0
- data/bin/omf_keygen +3 -3
- data/bin/omf_send_configure +114 -0
- data/bin/omf_send_request +19 -4
- data/example/engine_alt.rb +13 -7
- data/example/viz/garage_monitor.rb +69 -0
- data/example/viz/garage_viz.rb +52 -0
- data/example/viz/htdocs/image/garage.png +0 -0
- data/example/viz/htdocs/template/garage_banner.html +2 -0
- data/example/viz/layout.yaml +44 -0
- data/example/vm_alt.rb +5 -0
- data/lib/omf_common.rb +17 -8
- data/lib/omf_common/auth.rb +5 -0
- data/lib/omf_common/auth/certificate.rb +21 -2
- data/lib/omf_common/auth/certificate_store.rb +50 -20
- data/lib/omf_common/auth/ssh_pub_key_convert.rb +7 -0
- data/lib/omf_common/comm.rb +6 -1
- data/lib/omf_common/comm/amqp/amqp_communicator.rb +88 -12
- data/lib/omf_common/comm/amqp/amqp_file_transfer.rb +5 -0
- data/lib/omf_common/comm/amqp/amqp_topic.rb +37 -18
- data/lib/omf_common/comm/local/local_communicator.rb +5 -0
- data/lib/omf_common/comm/local/local_topic.rb +5 -0
- data/lib/omf_common/comm/topic.rb +32 -13
- data/lib/omf_common/comm/xmpp/communicator.rb +11 -1
- data/lib/omf_common/comm/xmpp/topic.rb +5 -0
- data/lib/omf_common/comm/xmpp/xmpp_mp.rb +5 -0
- data/lib/omf_common/command.rb +5 -0
- data/lib/omf_common/core_ext/string.rb +5 -0
- data/lib/omf_common/default_logging.rb +23 -5
- data/lib/omf_common/eventloop.rb +40 -23
- data/lib/omf_common/eventloop/em.rb +18 -5
- data/lib/omf_common/eventloop/local_evl.rb +18 -15
- data/lib/omf_common/exec_app.rb +44 -24
- data/lib/omf_common/key.rb +5 -0
- data/lib/omf_common/measure.rb +5 -0
- data/lib/omf_common/message.rb +5 -0
- data/lib/omf_common/message/json/json_message.rb +13 -5
- data/lib/omf_common/message/xml/message.rb +19 -4
- data/lib/omf_common/message/xml/relaxng_schema.rb +5 -0
- data/lib/omf_common/message/xml/topic_message.rb +5 -0
- data/lib/omf_common/version.rb +6 -1
- data/omf_common.gemspec +3 -2
- data/test/fixture/1st_level.pem +20 -0
- data/test/fixture/2nd_level.pem +19 -0
- data/test/fixture/3rd_level.pem +19 -0
- data/test/fixture/pubsub.rb +5 -0
- data/test/fixture/rc.pem +18 -0
- data/test/fixture/root.pem +17 -0
- data/test/omf_common/auth/certificate_spec.rb +27 -0
- data/test/omf_common/auth/certificate_store_spec.rb +58 -0
- data/test/omf_common/auth/ssh_pub_key_convert_spec.rb +5 -0
- data/test/omf_common/comm/topic_spec.rb +7 -1
- data/test/omf_common/comm/xmpp/communicator_spec.rb +5 -0
- data/test/omf_common/comm/xmpp/topic_spec.rb +5 -0
- data/test/omf_common/comm_spec.rb +5 -0
- data/test/omf_common/command_spec.rb +5 -0
- data/test/omf_common/core_ext/string_spec.rb +5 -0
- data/test/omf_common/message/xml/message_spec.rb +5 -0
- data/test/omf_common/message_spec.rb +8 -3
- data/test/test_helper.rb +5 -0
- metadata +48 -11
data/lib/omf_common/auth.rb
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# Copyright (c) 2012 National ICT Australia Limited (NICTA).
|
2
|
+
# This software may be used and distributed solely under the terms of the MIT license (License).
|
3
|
+
# You should find a copy of the License in LICENSE.TXT or at http://opensource.org/licenses/MIT.
|
4
|
+
# By downloading or using this software you accept the terms and the liability disclaimer in the License.
|
5
|
+
|
1
6
|
|
2
7
|
|
3
8
|
module OmfCommon
|
@@ -1,3 +1,8 @@
|
|
1
|
+
# Copyright (c) 2012 National ICT Australia Limited (NICTA).
|
2
|
+
# This software may be used and distributed solely under the terms of the MIT license (License).
|
3
|
+
# You should find a copy of the License in LICENSE.TXT or at http://opensource.org/licenses/MIT.
|
4
|
+
# By downloading or using this software you accept the terms and the liability disclaimer in the License.
|
5
|
+
|
1
6
|
require 'openssl'
|
2
7
|
require 'omf_common/auth'
|
3
8
|
require 'omf_common/auth/ssh_pub_key_convert'
|
@@ -32,9 +37,11 @@ module OmfCommon::Auth
|
|
32
37
|
# @param [String] pem is the content of existing x509 cert
|
33
38
|
# @param [OpenSSL::PKey::RSA|String] key is the private key which can be attached to the instance for signing.
|
34
39
|
def self.create_from_x509(pem, key = nil)
|
35
|
-
|
40
|
+
# Some command list generated cert can use \r\n as newline char
|
41
|
+
unless pem =~ /^-----BEGIN CERTIFICATE-----/
|
36
42
|
pem = "#{BEGIN_CERT}#{pem}#{END_CERT}"
|
37
43
|
end
|
44
|
+
|
38
45
|
cert = OpenSSL::X509::Certificate.new(pem)
|
39
46
|
|
40
47
|
key = OpenSSL::PKey::RSA.new(key) if key && key.is_a?(String)
|
@@ -64,7 +71,9 @@ module OmfCommon::Auth
|
|
64
71
|
|
65
72
|
# Create a X509 certificate
|
66
73
|
#
|
67
|
-
# @param [] address
|
74
|
+
# @param [String] address
|
75
|
+
# @param [String] subject
|
76
|
+
# @param [OpenSSL::PKey::RSA] key
|
68
77
|
# @return {cert, key}
|
69
78
|
#
|
70
79
|
def self._create_x509_cert(address, subject, key, digest = nil,
|
@@ -127,8 +136,18 @@ module OmfCommon::Auth
|
|
127
136
|
@cert ||= _create_x509_cert(@address, @subject, @key, @digest)[:cert]
|
128
137
|
end
|
129
138
|
|
139
|
+
# @param [OpenSSL::PKey::RSA|String] key is most likely the public key of the resource.
|
140
|
+
#
|
130
141
|
def create_for(address, name, type, domain = DEF_DOMAIN_NAME, duration = 3600, key = nil)
|
131
142
|
raise ArgumentError, "Address required" unless address
|
143
|
+
|
144
|
+
begin
|
145
|
+
key = OpenSSL::PKey::RSA.new(key) if key && key.is_a?(String)
|
146
|
+
rescue OpenSSL::PKey::RSAError
|
147
|
+
# It might be a SSH pub key, try that
|
148
|
+
key = OmfCommon::Auth::SSHPubKeyConvert.convert(key)
|
149
|
+
end
|
150
|
+
|
132
151
|
cert = self.class.create(address, name, type, domain, self, Time.now, duration, key)
|
133
152
|
CertificateStore.instance.register(cert, address)
|
134
153
|
cert
|
@@ -1,27 +1,19 @@
|
|
1
|
+
# Copyright (c) 2012 National ICT Australia Limited (NICTA).
|
2
|
+
# This software may be used and distributed solely under the terms of the MIT license (License).
|
3
|
+
# You should find a copy of the License in LICENSE.TXT or at http://opensource.org/licenses/MIT.
|
4
|
+
# By downloading or using this software you accept the terms and the liability disclaimer in the License.
|
5
|
+
|
1
6
|
require 'openssl'
|
7
|
+
require 'monitor'
|
2
8
|
|
3
9
|
require 'omf_common/auth'
|
4
10
|
|
5
|
-
#require 'singleton'
|
6
|
-
|
7
|
-
# module OmfCommon
|
8
|
-
# class Key
|
9
|
-
# include Singleton
|
10
|
-
#
|
11
|
-
# attr_accessor :private_key
|
12
|
-
#
|
13
|
-
# def import(filename)
|
14
|
-
# self.private_key = OpenSSL::PKey.read(File.read(filename))
|
15
|
-
# end
|
16
|
-
# end
|
17
|
-
# end
|
18
|
-
|
19
11
|
module OmfCommon::Auth
|
20
12
|
|
21
13
|
class MissingPrivateKeyException < AuthException; end
|
22
14
|
|
23
15
|
class CertificateStore
|
24
|
-
|
16
|
+
include MonitorMixin
|
25
17
|
|
26
18
|
@@instance = nil
|
27
19
|
|
@@ -38,12 +30,27 @@ module OmfCommon::Auth
|
|
38
30
|
end
|
39
31
|
|
40
32
|
def register(certificate, address = nil)
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
33
|
+
@@instance.synchronize do
|
34
|
+
begin
|
35
|
+
@x509_store.add_cert(certificate.to_x509) if @certs[address].nil? && @certs[certificate.subject].nil?
|
36
|
+
rescue OpenSSL::X509::StoreError => e
|
37
|
+
if e.message == "cert already in hash table"
|
38
|
+
raise "X509 cert '#{address}' already registered in X509 store"
|
39
|
+
else
|
40
|
+
raise e
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
address ||= certificate.address
|
45
|
+
|
46
|
+
if address
|
47
|
+
@certs[address] ||= certificate
|
48
|
+
else
|
49
|
+
debug "Register certificate without address - #{certificate}, is it a CA cert?"
|
50
|
+
end
|
51
|
+
|
52
|
+
@certs[certificate.subject] ||= certificate
|
45
53
|
end
|
46
|
-
@certs[certificate.subject] = certificate
|
47
54
|
end
|
48
55
|
|
49
56
|
def register_x509(cert_pem, address = nil)
|
@@ -57,15 +64,38 @@ module OmfCommon::Auth
|
|
57
64
|
@certs[url]
|
58
65
|
end
|
59
66
|
|
67
|
+
# @param [OpenSSL::X509::Certificate] cert
|
68
|
+
#
|
69
|
+
def verify(cert)
|
70
|
+
cert = cert.to_x509 if cert.kind_of? OmfCommon::Auth::Certificate
|
71
|
+
v_result = @x509_store.verify(cert)
|
72
|
+
warn "Cert verification failed: '#{@x509_store.error_string}'" unless v_result
|
73
|
+
v_result
|
74
|
+
end
|
75
|
+
|
76
|
+
# Load a set of CA certs into cert store from a given location
|
77
|
+
#
|
78
|
+
# @param [String] folder contains all the CA certs
|
79
|
+
#
|
80
|
+
def register_default_certs(folder)
|
81
|
+
Dir["#{folder}/*"].each do |cert|
|
82
|
+
register_x509(File.read(cert))
|
83
|
+
end
|
84
|
+
end
|
60
85
|
|
61
86
|
private
|
87
|
+
|
62
88
|
def initialize(opts)
|
89
|
+
@x509_store = OpenSSL::X509::Store.new
|
90
|
+
|
63
91
|
@certs = {}
|
64
92
|
if store = opts[:store]
|
65
93
|
else
|
66
94
|
@store = {private: {}, public: {}}
|
67
95
|
end
|
68
96
|
@serial = 0
|
97
|
+
|
98
|
+
super()
|
69
99
|
end
|
70
100
|
end # class
|
71
101
|
|
@@ -1,3 +1,8 @@
|
|
1
|
+
# Copyright (c) 2012 National ICT Australia Limited (NICTA).
|
2
|
+
# This software may be used and distributed solely under the terms of the MIT license (License).
|
3
|
+
# You should find a copy of the License in LICENSE.TXT or at http://opensource.org/licenses/MIT.
|
4
|
+
# By downloading or using this software you accept the terms and the liability disclaimer in the License.
|
5
|
+
|
1
6
|
require 'base64'
|
2
7
|
require 'openssl'
|
3
8
|
require 'omf_common/auth'
|
@@ -42,6 +47,8 @@ module OmfCommon::Auth
|
|
42
47
|
#
|
43
48
|
def self.convert(keystring)
|
44
49
|
(type, b64, id) = keystring.split(' ')
|
50
|
+
raise ArgumentError, "Invalid SSH public key '#{keystring}'" if b64.nil?
|
51
|
+
|
45
52
|
decoded_key = Base64.decode64(b64)
|
46
53
|
(n, bytes) = unpack_u32(decoded_key)
|
47
54
|
(keytype, bytes) = unpack_string(bytes, n)
|
data/lib/omf_common/comm.rb
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# Copyright (c) 2012 National ICT Australia Limited (NICTA).
|
2
|
+
# This software may be used and distributed solely under the terms of the MIT license (License).
|
3
|
+
# You should find a copy of the License in LICENSE.TXT or at http://opensource.org/licenses/MIT.
|
4
|
+
# By downloading or using this software you accept the terms and the liability disclaimer in the License.
|
5
|
+
|
1
6
|
require 'omf_common/comm/topic'
|
2
7
|
|
3
8
|
module OmfCommon
|
@@ -122,7 +127,7 @@ module OmfCommon
|
|
122
127
|
|
123
128
|
# Returning connection information
|
124
129
|
#
|
125
|
-
# @
|
130
|
+
# @return [Hash] connection information hash, with type, user and domain.
|
126
131
|
def conn_info
|
127
132
|
{ proto: nil, user: nil, domain: nil }
|
128
133
|
end
|
@@ -1,3 +1,8 @@
|
|
1
|
+
# Copyright (c) 2012 National ICT Australia Limited (NICTA).
|
2
|
+
# This software may be used and distributed solely under the terms of the MIT license (License).
|
3
|
+
# You should find a copy of the License in LICENSE.TXT or at http://opensource.org/licenses/MIT.
|
4
|
+
# By downloading or using this software you accept the terms and the liability disclaimer in the License.
|
5
|
+
|
1
6
|
require 'amqp'
|
2
7
|
require 'omf_common/comm/amqp/amqp_topic'
|
3
8
|
#require 'omf_common/comm/monkey_patches'
|
@@ -11,23 +16,25 @@ module OmfCommon
|
|
11
16
|
# # ignore arguments
|
12
17
|
# end
|
13
18
|
|
19
|
+
attr_reader :channel
|
20
|
+
|
14
21
|
# Initialize comms layer
|
15
22
|
#
|
16
23
|
def init(opts = {})
|
17
|
-
|
24
|
+
@opts = {
|
25
|
+
#:ssl (Hash) � TLS (SSL) parameters to use.
|
26
|
+
heartbeat: 20, # (Fixnum) � default: 0 � Connection heartbeat, in seconds. 0 means no heartbeat. Can also be configured server-side starting with RabbitMQ 3.0.
|
27
|
+
#:on_tcp_connection_failure (#call) � A callable object that will be run if connection to server fails
|
28
|
+
#:on_possible_authentication_failure (#call) � A callable object that will be run if authentication fails (see Authentication failure section)
|
29
|
+
reconnect_delay: 20 # (Fixnum) Delay in seconds before attempting reconnect on detected failure
|
30
|
+
}.merge(opts)
|
31
|
+
|
32
|
+
unless (@url = @opts.delete(:url))
|
18
33
|
raise "Missing 'url' option for AQMP layer"
|
19
34
|
end
|
20
35
|
@address_prefix = @url + '/'
|
21
|
-
|
22
|
-
|
23
|
-
@on_connected_procs.each do |proc|
|
24
|
-
proc.arity == 1 ? proc.call(self) : proc.call
|
25
|
-
end
|
26
|
-
|
27
|
-
OmfCommon.eventloop.on_stop do
|
28
|
-
connection.close
|
29
|
-
end
|
30
|
-
end
|
36
|
+
_connect()
|
37
|
+
#AMQP::Session#on_skipped_heartbeats callback that can be used to handle skipped heartbeats
|
31
38
|
super
|
32
39
|
end
|
33
40
|
|
@@ -44,13 +51,25 @@ module OmfCommon
|
|
44
51
|
@on_connected_procs << block
|
45
52
|
end
|
46
53
|
|
54
|
+
# register callbacks to be called when the underlying AMQP layer
|
55
|
+
# needs to reconnect to the AMQP server. This may require some additional
|
56
|
+
# repairs. If 'block' is nil, the callback is removed
|
57
|
+
#
|
58
|
+
def on_reconnect(key, &block)
|
59
|
+
if block.nil?
|
60
|
+
@on_reconnect.delete(key)
|
61
|
+
else
|
62
|
+
@on_reconnect[key] = block
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
47
66
|
# Create a new pubsub topic with additional configuration
|
48
67
|
#
|
49
68
|
# @param [String] topic Pubsub topic name
|
50
69
|
def create_topic(topic, opts = {})
|
51
70
|
raise "Topic can't be nil or empty" if topic.nil? || topic.empty?
|
52
71
|
opts = opts.dup
|
53
|
-
opts[:
|
72
|
+
opts[:communicator] = self
|
54
73
|
topic = topic.to_s
|
55
74
|
if topic.start_with? 'amqp:'
|
56
75
|
# absolute address
|
@@ -95,8 +114,65 @@ module OmfCommon
|
|
95
114
|
private
|
96
115
|
def initialize(opts = {})
|
97
116
|
@on_connected_procs = []
|
117
|
+
@on_reconnect = {}
|
98
118
|
super
|
99
119
|
end
|
120
|
+
|
121
|
+
def _connect()
|
122
|
+
last_reported_timestamp = nil
|
123
|
+
@session = ::AMQP.connect(@url, @opts) do |connection|
|
124
|
+
connection.on_tcp_connection_loss do |conn, settings|
|
125
|
+
now = Time.now
|
126
|
+
if last_reported_timestamp == nil || (now - last_reported_timestamp) > 60
|
127
|
+
warn "Lost connectivity. Trying to reconnect..."
|
128
|
+
last_reported_timestamp = now
|
129
|
+
end
|
130
|
+
conn.reconnect(false, 2)
|
131
|
+
end
|
132
|
+
@channel = ::AMQP::Channel.new(connection)
|
133
|
+
@channel.auto_recovery = true
|
134
|
+
|
135
|
+
|
136
|
+
@on_connected_procs.each do |proc|
|
137
|
+
proc.arity == 1 ? proc.call(self) : proc.call
|
138
|
+
end
|
139
|
+
|
140
|
+
OmfCommon.eventloop.on_stop do
|
141
|
+
connection.close
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
rec_delay = @opts[:reconnect_delay]
|
146
|
+
@session.on_tcp_connection_failure do
|
147
|
+
warn "Cannot connect to AMQP server '#{@url}'. Attempt to retry in #{rec_delay} sec"
|
148
|
+
@session = nil
|
149
|
+
OmfCommon.eventloop.after(rec_delay) do
|
150
|
+
info 'Retrying'
|
151
|
+
_connect
|
152
|
+
end
|
153
|
+
end
|
154
|
+
# @session.on_tcp_connection_loss do
|
155
|
+
# _reconnect "Appear to have lost tcp connection. Attempt to reconnect in #{rec_delay} sec"
|
156
|
+
# end
|
157
|
+
# @session.on_skipped_heartbeats do
|
158
|
+
# _reconnect "Appear to have lost heartbeat. Attempt to reconnect in #{rec_delay} sec"
|
159
|
+
# end
|
160
|
+
@session.on_recovery do
|
161
|
+
info 'Recovered!'
|
162
|
+
last_reported_timestamp = nil
|
163
|
+
@on_reconnect.values.each do |block|
|
164
|
+
block.call()
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# def _reconnect(warn_message = nil)
|
170
|
+
# warn(warn_message) if warn_message
|
171
|
+
# OmfCommon.eventloop.after(@opts[:reconnect_delay]) do
|
172
|
+
# info 'Reconnecting'
|
173
|
+
# @session.reconnect
|
174
|
+
# end
|
175
|
+
# end
|
100
176
|
end
|
101
177
|
end
|
102
178
|
end
|
@@ -1,3 +1,8 @@
|
|
1
|
+
# Copyright (c) 2012 National ICT Australia Limited (NICTA).
|
2
|
+
# This software may be used and distributed solely under the terms of the MIT license (License).
|
3
|
+
# You should find a copy of the License in LICENSE.TXT or at http://opensource.org/licenses/MIT.
|
4
|
+
# By downloading or using this software you accept the terms and the liability disclaimer in the License.
|
5
|
+
|
1
6
|
require 'set'
|
2
7
|
require 'monitor'
|
3
8
|
|
@@ -1,3 +1,8 @@
|
|
1
|
+
# Copyright (c) 2012 National ICT Australia Limited (NICTA).
|
2
|
+
# This software may be used and distributed solely under the terms of the MIT license (License).
|
3
|
+
# You should find a copy of the License in LICENSE.TXT or at http://opensource.org/licenses/MIT.
|
4
|
+
# By downloading or using this software you accept the terms and the liability disclaimer in the License.
|
5
|
+
|
1
6
|
|
2
7
|
|
3
8
|
module OmfCommon
|
@@ -8,17 +13,17 @@ module OmfCommon
|
|
8
13
|
def to_s
|
9
14
|
"AMQP::Topic<#{id}>"
|
10
15
|
end
|
11
|
-
|
16
|
+
|
12
17
|
def address
|
13
18
|
@address
|
14
19
|
end
|
15
|
-
|
20
|
+
|
16
21
|
# Call 'block' when topic is subscribed to underlying messaging
|
17
|
-
# infrastructure.
|
22
|
+
# infrastructure.
|
18
23
|
#
|
19
24
|
def on_subscribed(&block)
|
20
25
|
return unless block
|
21
|
-
|
26
|
+
|
22
27
|
call_now = false
|
23
28
|
@lock.synchronize do
|
24
29
|
if @subscribed
|
@@ -30,24 +35,35 @@ module OmfCommon
|
|
30
35
|
if call_now
|
31
36
|
after(0, &block)
|
32
37
|
end
|
33
|
-
end
|
34
|
-
|
35
|
-
|
38
|
+
end
|
39
|
+
|
40
|
+
|
36
41
|
private
|
37
|
-
|
42
|
+
|
38
43
|
def initialize(id, opts = {})
|
39
|
-
unless
|
40
|
-
raise "Missing :
|
44
|
+
unless @communicator = opts.delete(:communicator)
|
45
|
+
raise "Missing :communicator option"
|
41
46
|
end
|
42
47
|
super
|
43
48
|
@address = opts[:address]
|
44
|
-
@exchange = channel.topic(id, :auto_delete => true)
|
45
49
|
@lock = Monitor.new
|
46
50
|
@subscribed = false
|
47
51
|
@on_subscribed_handlers = []
|
48
|
-
|
49
|
-
#
|
50
|
-
|
52
|
+
|
53
|
+
# @communicator.on_reconnect(self) do
|
54
|
+
# info "Resubscribe '#{self}'"
|
55
|
+
# _init_amqp
|
56
|
+
# end
|
57
|
+
_init_amqp
|
58
|
+
end
|
59
|
+
|
60
|
+
def _init_amqp()
|
61
|
+
channel = @communicator.channel
|
62
|
+
@exchange = channel.topic(id, :auto_delete => true)
|
63
|
+
# @exchange.on_connection_interruption do |ex|
|
64
|
+
# warn "Exchange #{ex.name} detected connection interruption"
|
65
|
+
# @exchange = nil
|
66
|
+
# end
|
51
67
|
channel.queue("", :exclusive => true) do |queue|
|
52
68
|
#puts "QQ1(#{id}): #{queue}"
|
53
69
|
queue.bind(@exchange)
|
@@ -70,15 +86,18 @@ module OmfCommon
|
|
70
86
|
end
|
71
87
|
end
|
72
88
|
end
|
73
|
-
|
74
|
-
|
89
|
+
|
75
90
|
def _send_message(msg, block = nil)
|
76
91
|
super
|
77
92
|
content_type, content = msg.marshall(self)
|
78
93
|
debug "(#{id}) Send message (#{content_type}) #{msg.inspect}"
|
79
|
-
@exchange
|
94
|
+
if @exchange
|
95
|
+
@exchange.publish(content, content_type: content_type, message_id: msg.mid)
|
96
|
+
else
|
97
|
+
warn "Unavailable AMQP channel. Dropping message '#{msg}'"
|
98
|
+
end
|
80
99
|
end
|
81
100
|
end # class
|
82
|
-
end # module
|
101
|
+
end # module
|
83
102
|
end # module
|
84
103
|
end # module
|