msgr 1.2.0 → 1.3.0
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.
- checksums.yaml +4 -4
- data/.editorconfig +8 -0
- data/.github/workflows/build.yml +52 -0
- data/.github/workflows/lint.yml +20 -0
- data/.rubocop.yml +9 -48
- data/.travis.yml +21 -35
- data/Appraisals +18 -0
- data/CHANGELOG.md +11 -1
- data/Gemfile +8 -15
- data/README.md +8 -20
- data/Rakefile +5 -5
- data/bin/msgr +1 -0
- data/gemfiles/rails_5.2.gemfile +14 -0
- data/gemfiles/rails_6.0.gemfile +14 -0
- data/gemfiles/rails_6.1.gemfile +14 -0
- data/gemfiles/rails_master.gemfile +14 -0
- data/lib/msgr.rb +1 -0
- data/lib/msgr/binding.rb +13 -8
- data/lib/msgr/channel.rb +5 -3
- data/lib/msgr/cli.rb +18 -11
- data/lib/msgr/client.rb +17 -20
- data/lib/msgr/connection.rb +13 -1
- data/lib/msgr/consumer.rb +2 -3
- data/lib/msgr/dispatcher.rb +7 -9
- data/lib/msgr/logging.rb +2 -0
- data/lib/msgr/message.rb +1 -2
- data/lib/msgr/railtie.rb +14 -69
- data/lib/msgr/route.rb +1 -4
- data/lib/msgr/routes.rb +2 -0
- data/lib/msgr/tasks/msgr/drain.rake +11 -0
- data/lib/msgr/test_pool.rb +1 -3
- data/lib/msgr/version.rb +1 -1
- data/msgr.gemspec +2 -6
- data/scripts/simple_test.rb +2 -3
- data/spec/fixtures/{msgr-routes-test-1.rb → msgr_routes_test_1.rb} +0 -0
- data/spec/integration/dummy/Rakefile +1 -1
- data/spec/{msgr/support/.keep → integration/dummy/app/assets/config/manifest.js} +0 -0
- data/spec/integration/dummy/bin/bundle +1 -1
- data/spec/integration/dummy/bin/rails +1 -1
- data/spec/integration/dummy/config/application.rb +1 -1
- data/spec/integration/dummy/config/boot.rb +2 -2
- data/spec/integration/dummy/config/environment.rb +1 -1
- data/spec/integration/dummy/config/rabbitmq.yml +1 -1
- data/spec/integration/msgr/dispatcher_spec.rb +28 -12
- data/spec/integration/msgr/railtie_spec.rb +10 -120
- data/spec/integration/spec_helper.rb +2 -3
- data/spec/integration/{msgr_spec.rb → test_controller_spec.rb} +1 -1
- data/spec/unit/msgr/client_spec.rb +88 -0
- data/spec/{msgr → unit}/msgr/connection_spec.rb +1 -1
- data/spec/{msgr → unit}/msgr/consumer_spec.rb +0 -0
- data/spec/unit/msgr/dispatcher_spec.rb +45 -0
- data/spec/{msgr → unit}/msgr/route_spec.rb +15 -14
- data/spec/{msgr → unit}/msgr/routes_spec.rb +32 -35
- data/spec/{msgr → unit}/msgr_spec.rb +25 -16
- data/spec/{msgr → unit}/spec_helper.rb +1 -1
- data/spec/unit/support/.keep +0 -0
- metadata +37 -33
- data/gemfiles/Gemfile.rails-4-2 +0 -7
- data/gemfiles/Gemfile.rails-5-0 +0 -7
- data/gemfiles/Gemfile.rails-5-1 +0 -7
- data/gemfiles/Gemfile.rails-5-2 +0 -7
- data/gemfiles/Gemfile.rails-master +0 -14
- data/spec/msgr/msgr/client_spec.rb +0 -60
- data/spec/msgr/msgr/dispatcher_spec.rb +0 -44
- data/spec/support/setup.rb +0 -29
data/lib/msgr.rb
CHANGED
data/lib/msgr/binding.rb
CHANGED
@@ -4,7 +4,14 @@ module Msgr
|
|
4
4
|
class Binding
|
5
5
|
include Logging
|
6
6
|
|
7
|
-
attr_reader
|
7
|
+
attr_reader(
|
8
|
+
:channel,
|
9
|
+
:connection,
|
10
|
+
:dispatcher,
|
11
|
+
:queue,
|
12
|
+
:route,
|
13
|
+
:subscription
|
14
|
+
)
|
8
15
|
|
9
16
|
def initialize(connection, route, dispatcher)
|
10
17
|
@connection = connection
|
@@ -43,13 +50,11 @@ module Msgr
|
|
43
50
|
|
44
51
|
def subscribe
|
45
52
|
@subscription = queue.subscribe(manual_ack: true) do |*args|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
"#{err}\n#{err.backtrace.join("\n")}"
|
52
|
-
end
|
53
|
+
dispatcher.call Message.new(channel, *args, route)
|
54
|
+
rescue StandardError => e
|
55
|
+
log(:error) do
|
56
|
+
"Rescued error from subscribe: #{e.class.name}: " \
|
57
|
+
"#{e}\n#{e.backtrace.join("\n")}"
|
53
58
|
end
|
54
59
|
end
|
55
60
|
end
|
data/lib/msgr/channel.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Msgr
|
2
4
|
class Channel
|
3
5
|
include Logging
|
@@ -26,8 +28,8 @@ module Msgr
|
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
29
|
-
def queue(name)
|
30
|
-
@channel.queue(prefix(name), durable: true).tap do |queue|
|
31
|
+
def queue(name, **opts)
|
32
|
+
@channel.queue(prefix(name), durable: true, **opts).tap do |queue|
|
31
33
|
log(:debug) do
|
32
34
|
"Create queue #{queue.name} (durable: #{queue.durable?}, " \
|
33
35
|
"auto_delete: #{queue.auto_delete?})"
|
@@ -62,4 +64,4 @@ module Msgr
|
|
62
64
|
@channel.close if @channel.open?
|
63
65
|
end
|
64
66
|
end
|
65
|
-
end
|
67
|
+
end
|
data/lib/msgr/cli.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'optionparser'
|
2
4
|
|
3
5
|
module Msgr
|
@@ -8,7 +10,8 @@ module Msgr
|
|
8
10
|
@options = options
|
9
11
|
|
10
12
|
if !File.exist?(options[:require]) ||
|
11
|
-
|
13
|
+
(File.directory?(options[:require]) &&
|
14
|
+
!File.exist?("#{options[:require]}/config/application.rb"))
|
12
15
|
raise <<~ERR
|
13
16
|
Rails application or required ruby file not found: #{options[:require]}
|
14
17
|
ERR
|
@@ -22,15 +25,13 @@ module Msgr
|
|
22
25
|
require 'rails'
|
23
26
|
if ::Rails::VERSION::MAJOR == 4
|
24
27
|
require File.expand_path("#{options[:require]}/config/application.rb")
|
25
|
-
::Rails::Application.initializer
|
28
|
+
::Rails::Application.initializer 'msgr.eager_load' do
|
26
29
|
::Rails.application.config.eager_load = true
|
27
30
|
end
|
28
|
-
require 'msgr/railtie'
|
29
|
-
require File.expand_path("#{options[:require]}/config/environment.rb")
|
30
|
-
else
|
31
|
-
require 'msgr/railtie'
|
32
|
-
require File.expand_path("#{options[:require]}/config/environment.rb")
|
33
31
|
end
|
32
|
+
|
33
|
+
require 'msgr/railtie'
|
34
|
+
require File.expand_path("#{options[:require]}/config/environment.rb")
|
34
35
|
else
|
35
36
|
require(options[:require])
|
36
37
|
end
|
@@ -43,7 +44,7 @@ module Msgr
|
|
43
44
|
Msgr.logger = Logger.new(STDOUT)
|
44
45
|
Msgr.client.start
|
45
46
|
|
46
|
-
while readable = IO.select([r])
|
47
|
+
while (readable = IO.select([r]))
|
47
48
|
case readable.first[0].gets.strip
|
48
49
|
when 'INT', 'TERM'
|
49
50
|
Msgr.client.stop
|
@@ -61,18 +62,24 @@ module Msgr
|
|
61
62
|
|
62
63
|
private
|
63
64
|
|
64
|
-
def parse(
|
65
|
+
def parse(_argv)
|
65
66
|
options = {
|
66
67
|
require: Dir.pwd,
|
67
68
|
environment: 'development'
|
68
69
|
}
|
69
70
|
|
70
71
|
OptionParser.new do |o|
|
71
|
-
o.on
|
72
|
+
o.on(
|
73
|
+
'-r', '--require [PATH|DIR]',
|
74
|
+
'Location of Rails application (default to current directory)'
|
75
|
+
) do |arg|
|
72
76
|
options[:require] = arg
|
73
77
|
end
|
74
78
|
|
75
|
-
o.on
|
79
|
+
o.on(
|
80
|
+
'-e', '--environment [env]',
|
81
|
+
'Rails environment (default to development)'
|
82
|
+
) do |arg|
|
76
83
|
options[:environment] = arg
|
77
84
|
end
|
78
85
|
end.parse!
|
data/lib/msgr/client.rb
CHANGED
@@ -2,15 +2,14 @@
|
|
2
2
|
|
3
3
|
require 'uri'
|
4
4
|
require 'cgi'
|
5
|
+
require 'json'
|
5
6
|
|
6
7
|
module Msgr
|
7
|
-
# rubocop:disable Metrics/ClassLength
|
8
8
|
class Client
|
9
9
|
include Logging
|
10
10
|
|
11
11
|
attr_reader :config
|
12
12
|
|
13
|
-
# rubocop:disable MethodLength
|
14
13
|
def initialize(config = {})
|
15
14
|
@config = {
|
16
15
|
host: '127.0.0.1',
|
@@ -18,7 +17,7 @@ module Msgr
|
|
18
17
|
max: 2
|
19
18
|
}
|
20
19
|
|
21
|
-
@config.merge! parse(config.delete(:uri)) if config
|
20
|
+
@config.merge! parse(config.delete(:uri)) if config[:uri]
|
22
21
|
@config.merge! config.symbolize_keys
|
23
22
|
|
24
23
|
@mutex = ::Mutex.new
|
@@ -27,12 +26,7 @@ module Msgr
|
|
27
26
|
|
28
27
|
log(:debug) { "Created new client on process ##{@pid}..." }
|
29
28
|
end
|
30
|
-
# rubocop:enable all
|
31
29
|
|
32
|
-
# rubocop:disable AbcSize
|
33
|
-
# rubocop:disable MethodLength
|
34
|
-
# rubocop:disable PerceivedComplexity
|
35
|
-
# rubocop:disable CyclomaticComplexity
|
36
30
|
def uri
|
37
31
|
@uri = begin
|
38
32
|
uri = ::URI.parse('amqp://localhost')
|
@@ -50,7 +44,6 @@ module Msgr
|
|
50
44
|
uri
|
51
45
|
end
|
52
46
|
end
|
53
|
-
# rubocop:enable all
|
54
47
|
|
55
48
|
def running?
|
56
49
|
mutex.synchronize do
|
@@ -59,7 +52,6 @@ module Msgr
|
|
59
52
|
end
|
60
53
|
end
|
61
54
|
|
62
|
-
# rubocop:disable AbcSize
|
63
55
|
def start
|
64
56
|
mutex.synchronize do
|
65
57
|
check_process!
|
@@ -72,7 +64,6 @@ module Msgr
|
|
72
64
|
connection.bind(@routes)
|
73
65
|
end
|
74
66
|
end
|
75
|
-
# rubocop:enable all
|
76
67
|
|
77
68
|
def connect
|
78
69
|
mutex.synchronize do
|
@@ -85,7 +76,6 @@ module Msgr
|
|
85
76
|
end
|
86
77
|
end
|
87
78
|
|
88
|
-
# rubocop:disable AbcSize
|
89
79
|
def stop(opts = {})
|
90
80
|
mutex.synchronize do
|
91
81
|
check_process!
|
@@ -100,7 +90,6 @@ module Msgr
|
|
100
90
|
reset
|
101
91
|
end
|
102
92
|
end
|
103
|
-
# rubocop:enable all
|
104
93
|
|
105
94
|
def purge(release: false)
|
106
95
|
mutex.synchronize do
|
@@ -112,6 +101,15 @@ module Msgr
|
|
112
101
|
end
|
113
102
|
end
|
114
103
|
|
104
|
+
##
|
105
|
+
# Purge all queues known to Msgr, if they exist.
|
106
|
+
#
|
107
|
+
def drain
|
108
|
+
@routes.each do |route|
|
109
|
+
connection.purge_queue(route.name)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
115
113
|
def publish(payload, opts = {})
|
116
114
|
mutex.synchronize do
|
117
115
|
check_process!
|
@@ -149,6 +147,7 @@ module Msgr
|
|
149
147
|
|
150
148
|
def check_process!
|
151
149
|
return if ::Process.pid == @pid
|
150
|
+
|
152
151
|
log(:warn) do
|
153
152
|
"Fork detected. Reset internal state. (Old PID: #{@pid} / " \
|
154
153
|
"New PID: #{::Process.pid}"
|
@@ -178,22 +177,20 @@ module Msgr
|
|
178
177
|
@dispatcher = nil
|
179
178
|
end
|
180
179
|
|
181
|
-
# rubocop:disable AbcSize
|
182
180
|
def parse(uri)
|
183
181
|
# Legacy parsing of URI configuration; does not follow usual
|
184
182
|
# AMQP vhost encoding but used regular URL path
|
185
183
|
uri = ::URI.parse(uri)
|
186
184
|
|
187
185
|
config = {}
|
188
|
-
config[:user]
|
189
|
-
config[:pass]
|
190
|
-
config[:host]
|
191
|
-
config[:port]
|
192
|
-
config[:vhost] ||= uri.path
|
186
|
+
config[:user] ||= uri.user if uri.user
|
187
|
+
config[:pass] ||= uri.password if uri.password
|
188
|
+
config[:host] ||= uri.host if uri.host
|
189
|
+
config[:port] ||= uri.port if uri.port
|
190
|
+
config[:vhost] ||= uri.path unless uri.path.empty?
|
193
191
|
config[:ssl] ||= uri.scheme.casecmp('amqps').zero?
|
194
192
|
|
195
193
|
config
|
196
194
|
end
|
197
|
-
# rubocop:enable all
|
198
195
|
end
|
199
196
|
end
|
data/lib/msgr/connection.rb
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
require 'bunny'
|
4
4
|
|
5
5
|
module Msgr
|
6
|
-
# rubocop:disable Metrics/ClassLength
|
7
6
|
class Connection
|
8
7
|
include Logging
|
9
8
|
|
@@ -49,6 +48,7 @@ module Msgr
|
|
49
48
|
|
50
49
|
def release
|
51
50
|
return if bindings.empty?
|
51
|
+
|
52
52
|
log(:debug) { "Release bindings (#{bindings.size})..." }
|
53
53
|
|
54
54
|
bindings.each(&:release)
|
@@ -56,6 +56,7 @@ module Msgr
|
|
56
56
|
|
57
57
|
def delete
|
58
58
|
return if bindings.empty?
|
59
|
+
|
59
60
|
log(:debug) { "Delete bindings (#{bindings.size})..." }
|
60
61
|
|
61
62
|
bindings.each(&:delete)
|
@@ -63,11 +64,22 @@ module Msgr
|
|
63
64
|
|
64
65
|
def purge(**kwargs)
|
65
66
|
return if bindings.empty?
|
67
|
+
|
66
68
|
log(:debug) { "Purge bindings (#{bindings.size})..." }
|
67
69
|
|
68
70
|
bindings.each {|b| b.purge(**kwargs) }
|
69
71
|
end
|
70
72
|
|
73
|
+
def purge_queue(name)
|
74
|
+
# Creating the queue in passive mode ensures that queues that do not exist
|
75
|
+
# won't be created just to purge them.
|
76
|
+
# That requires creating a new channel every time, as exceptions (on
|
77
|
+
# missing queues) invalidate the channel.
|
78
|
+
channel.queue(name, passive: true).purge
|
79
|
+
rescue Bunny::NotFound
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
|
71
83
|
def bindings
|
72
84
|
@bindings ||= []
|
73
85
|
end
|
data/lib/msgr/consumer.rb
CHANGED
@@ -5,6 +5,7 @@ module Msgr
|
|
5
5
|
include Logging
|
6
6
|
|
7
7
|
attr_reader :message
|
8
|
+
|
8
9
|
delegate :payload, to: :@message
|
9
10
|
delegate :action, to: :'@message.route'
|
10
11
|
delegate :consumer, to: :'@message.consumer'
|
@@ -14,9 +15,7 @@ module Msgr
|
|
14
15
|
@auto_ack || @auto_ack.nil?
|
15
16
|
end
|
16
17
|
|
17
|
-
|
18
|
-
@auto_ack = val
|
19
|
-
end
|
18
|
+
attr_writer :auto_ack
|
20
19
|
end
|
21
20
|
|
22
21
|
def dispatch(message)
|
data/lib/msgr/dispatcher.rb
CHANGED
@@ -27,9 +27,6 @@ module Msgr
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
# rubocop:disable Metrics/AbcSize
|
31
|
-
# rubocop:disable Metrics/MethodLength
|
32
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
33
30
|
def dispatch(message)
|
34
31
|
consumer_class = Object.const_get message.route.consumer
|
35
32
|
|
@@ -37,17 +34,18 @@ module Msgr
|
|
37
34
|
|
38
35
|
consumer_class.new.dispatch message
|
39
36
|
|
40
|
-
# Acknowledge message
|
41
|
-
|
42
|
-
|
37
|
+
# Acknowledge message only if it is not already acknowledged and auto
|
38
|
+
# acknowledgment is enabled.
|
39
|
+
message.ack unless message.acked? || !consumer_class.auto_ack?
|
40
|
+
rescue StandardError => e
|
43
41
|
message.nack unless message.acked?
|
44
42
|
|
45
43
|
log(:error) do
|
46
|
-
"Dispatcher error: #{
|
47
|
-
|
44
|
+
"Dispatcher error: #{e.class.name}: #{e}\n" +
|
45
|
+
e.backtrace.join("\n")
|
48
46
|
end
|
49
47
|
|
50
|
-
raise
|
48
|
+
raise e if config[:raise_exceptions]
|
51
49
|
ensure
|
52
50
|
if defined?(ActiveRecord) &&
|
53
51
|
ActiveRecord::Base.connection_pool.active_connection?
|
data/lib/msgr/logging.rb
CHANGED
data/lib/msgr/message.rb
CHANGED
@@ -11,8 +11,7 @@ module Msgr
|
|
11
11
|
@payload = payload
|
12
12
|
@route = route
|
13
13
|
|
14
|
-
# rubocop:disable Style/GuardClause
|
15
|
-
if content_type == 'application/json'
|
14
|
+
if content_type == 'application/json' # rubocop:disable Style/GuardClause
|
16
15
|
@payload = JSON.parse(payload)
|
17
16
|
@payload.symbolize_keys! if @payload.respond_to? :symbolize_keys!
|
18
17
|
end
|
data/lib/msgr/railtie.rb
CHANGED
@@ -4,6 +4,11 @@ module Msgr
|
|
4
4
|
class Railtie < ::Rails::Railtie
|
5
5
|
config.msgr = ActiveSupport::OrderedOptions.new
|
6
6
|
|
7
|
+
DEFAULT_OPTIONS = {
|
8
|
+
checkcredentials: true,
|
9
|
+
routing_file: "#{Rails.root}/config/msgr.rb"
|
10
|
+
}.freeze
|
11
|
+
|
7
12
|
if File.exist?("#{Rails.root}/app/consumers")
|
8
13
|
config.autoload_paths << File.expand_path("#{Rails.root}/app/consumers")
|
9
14
|
end
|
@@ -12,84 +17,24 @@ module Msgr
|
|
12
17
|
app.config.msgr.logger ||= Rails.logger
|
13
18
|
end
|
14
19
|
|
15
|
-
# Start msgr
|
16
20
|
initializer 'msgr.start' do
|
17
21
|
config.after_initialize do |app|
|
18
22
|
Msgr.logger = app.config.msgr.logger
|
19
23
|
|
20
|
-
self.class.load
|
24
|
+
self.class.load(app.config_for(:rabbitmq))
|
21
25
|
end
|
22
26
|
end
|
23
27
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
return unless cfg # no config given -> does not load Msgr
|
28
|
-
|
29
|
-
Msgr.config = cfg
|
30
|
-
Msgr.client.connect if cfg[:checkcredentials]
|
31
|
-
Msgr.start if cfg[:autostart]
|
32
|
-
end
|
33
|
-
|
34
|
-
def parse_config(cfg)
|
35
|
-
unless cfg.is_a? Hash
|
36
|
-
Rails.logger.warn '[Msgr] Could not load rabbitmq config: Config must be a Hash'
|
37
|
-
return nil
|
38
|
-
end
|
39
|
-
|
40
|
-
unless cfg[Rails.env].is_a?(Hash)
|
41
|
-
Rails.logger.warn "Could not load rabbitmq config for environment \"#{Rails.env}\": is not a Hash"
|
42
|
-
return nil
|
43
|
-
end
|
44
|
-
|
45
|
-
cfg = HashWithIndifferentAccess.new cfg[Rails.env]
|
46
|
-
unless cfg[:uri]
|
47
|
-
raise ArgumentError.new('Could not load rabbitmq environment config: URI missing.')
|
48
|
-
end
|
49
|
-
|
50
|
-
case cfg[:autostart]
|
51
|
-
when true, 'true', 'enabled'
|
52
|
-
cfg[:autostart] = true
|
53
|
-
when false, 'false', 'disabled', nil
|
54
|
-
cfg[:autostart] = false
|
55
|
-
else
|
56
|
-
raise ArgumentError.new("Invalid value for rabbitmq config autostart: \"#{cfg[:autostart]}\"")
|
57
|
-
end
|
58
|
-
|
59
|
-
case cfg[:checkcredentials]
|
60
|
-
when true, 'true', 'enabled', nil
|
61
|
-
cfg[:checkcredentials] = true
|
62
|
-
when false, 'false', 'disabled'
|
63
|
-
cfg[:checkcredentials] = false
|
64
|
-
else
|
65
|
-
raise ArgumentError.new("Invalid value for rabbitmq config checkcredentials: \"#{cfg[:checkcredentials]}\"")
|
66
|
-
end
|
67
|
-
|
68
|
-
case cfg[:raise_exceptions]
|
69
|
-
when true, 'true', 'enabled'
|
70
|
-
cfg[:raise_exceptions] = true
|
71
|
-
when false, 'false', 'disabled', nil
|
72
|
-
cfg[:raise_exceptions] = false
|
73
|
-
else
|
74
|
-
raise ArgumentError.new("Invalid value for rabbitmq config raise_exceptions: \"#{cfg[:raise_exceptions]}\"")
|
75
|
-
end
|
76
|
-
|
77
|
-
cfg[:routing_file] ||= Rails.root.join('config/msgr.rb').to_s
|
78
|
-
cfg
|
79
|
-
end
|
80
|
-
|
81
|
-
def load_config(options)
|
82
|
-
if options.rabbitmq_config || !Rails.application.respond_to?(:config_for)
|
83
|
-
load_file options.rabbitmq_config || Rails.root.join('config', 'rabbitmq.yml')
|
84
|
-
else
|
85
|
-
conf = Rails.application.config_for :rabbitmq
|
28
|
+
rake_tasks do
|
29
|
+
load File.expand_path('tasks/msgr/drain.rake', __dir__)
|
30
|
+
end
|
86
31
|
|
87
|
-
|
88
|
-
|
89
|
-
|
32
|
+
class << self
|
33
|
+
def load(config)
|
34
|
+
config = DEFAULT_OPTIONS.merge(config)
|
90
35
|
|
91
|
-
|
92
|
-
|
36
|
+
Msgr.config = config
|
37
|
+
Msgr.client.connect if config.fetch(:checkcredentials)
|
93
38
|
end
|
94
39
|
end
|
95
40
|
end
|