nsq-krakow 0.1.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.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +84 -0
  3. data/CONTRIBUTING.md +25 -0
  4. data/LICENSE +13 -0
  5. data/README.md +249 -0
  6. data/krakow.gemspec +22 -0
  7. data/lib/krakow.rb +25 -0
  8. data/lib/krakow/command.rb +89 -0
  9. data/lib/krakow/command/auth.rb +36 -0
  10. data/lib/krakow/command/cls.rb +24 -0
  11. data/lib/krakow/command/fin.rb +31 -0
  12. data/lib/krakow/command/identify.rb +55 -0
  13. data/lib/krakow/command/mpub.rb +39 -0
  14. data/lib/krakow/command/nop.rb +14 -0
  15. data/lib/krakow/command/pub.rb +37 -0
  16. data/lib/krakow/command/rdy.rb +31 -0
  17. data/lib/krakow/command/req.rb +32 -0
  18. data/lib/krakow/command/sub.rb +36 -0
  19. data/lib/krakow/command/touch.rb +31 -0
  20. data/lib/krakow/connection.rb +417 -0
  21. data/lib/krakow/connection_features.rb +10 -0
  22. data/lib/krakow/connection_features/deflate.rb +82 -0
  23. data/lib/krakow/connection_features/snappy_frames.rb +129 -0
  24. data/lib/krakow/connection_features/ssl.rb +75 -0
  25. data/lib/krakow/consumer.rb +355 -0
  26. data/lib/krakow/consumer/queue.rb +151 -0
  27. data/lib/krakow/discovery.rb +57 -0
  28. data/lib/krakow/distribution.rb +229 -0
  29. data/lib/krakow/distribution/default.rb +159 -0
  30. data/lib/krakow/exceptions.rb +30 -0
  31. data/lib/krakow/frame_type.rb +66 -0
  32. data/lib/krakow/frame_type/error.rb +26 -0
  33. data/lib/krakow/frame_type/message.rb +74 -0
  34. data/lib/krakow/frame_type/response.rb +26 -0
  35. data/lib/krakow/ksocket.rb +102 -0
  36. data/lib/krakow/producer.rb +162 -0
  37. data/lib/krakow/producer/http.rb +224 -0
  38. data/lib/krakow/utils.rb +9 -0
  39. data/lib/krakow/utils/lazy.rb +125 -0
  40. data/lib/krakow/utils/logging.rb +43 -0
  41. data/lib/krakow/version.rb +4 -0
  42. metadata +184 -0
@@ -0,0 +1,36 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+ class Command
5
+ # Publish single message
6
+ class Auth < Command
7
+
8
+ # @!group Attributes
9
+
10
+ # @!macro [attach] attribute
11
+ # @!method $1
12
+ # @return [$2] the $1 $0
13
+ # @!method $1?
14
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
15
+ attribute :secret, String, :required => true
16
+
17
+ # @!endgroup
18
+
19
+ def to_line
20
+ scrt = secret.to_s
21
+ [name, "\n", scrt.bytesize, scrt].pack('a*a*a*a*l>a*')
22
+ end
23
+
24
+ class << self
25
+ def ok
26
+ %w(OK)
27
+ end
28
+
29
+ def error
30
+ %w(E_AUTH_FAILED E_UNAUTHORIZED)
31
+ end
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,24 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+ class Command
5
+ # Close connection
6
+ class Cls < Command
7
+
8
+ def to_line
9
+ "#{name}\n"
10
+ end
11
+
12
+ class << self
13
+ def ok
14
+ %w(CLOSE_WAIT)
15
+ end
16
+
17
+ def error
18
+ %w(E_INVALID)
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,31 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+ class Command
5
+ # Finish a message
6
+ class Fin < Command
7
+
8
+ # @!group Attributes
9
+
10
+ # @!macro [attach] attribute
11
+ # @!method $1
12
+ # @return [$2] the $1 $0
13
+ # @!method $1?
14
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
15
+ attribute :message_id, String, :required => true
16
+
17
+ # @!endgroup
18
+
19
+ def to_line
20
+ "#{name} #{message_id}\n"
21
+ end
22
+
23
+ class << self
24
+ def error
25
+ %w(E_INVALID E_FIN_FAILED)
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,55 @@
1
+ require 'multi_json'
2
+ require 'krakow'
3
+
4
+ module Krakow
5
+ class Command
6
+ # Update client metadata on server / negotiate features
7
+ class Identify < Command
8
+
9
+ # @!group Attributes
10
+
11
+ # @!macro [attach] attribute
12
+ # @!method $1
13
+ # @return [$2] the $1 $0
14
+ # @!method $1?
15
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
16
+ attribute :short_id, [String, Numeric], :required => true
17
+ attribute :long_id, [String, Numeric], :required => true
18
+ attribute :feature_negotiation, [TrueClass, FalseClass]
19
+ attribute :heartbeat_interval, Numeric
20
+ attribute :output_buffer_size, Integer
21
+ attribute :output_buffer_timeout, Integer
22
+ attribute :tls_v1, [TrueClass, FalseClass]
23
+ attribute :snappy, [TrueClass, FalseClass]
24
+ attribute :deflate, [TrueClass, FalseClass]
25
+ attribute :deflate_level, Integer
26
+ attribute :sample_rate, Integer
27
+
28
+ # @!endgroup
29
+
30
+ def to_line
31
+ filtered = Hash[*
32
+ arguments.map do |key, value|
33
+ unless(value.nil?)
34
+ [key, value]
35
+ end
36
+ end.compact.flatten
37
+ ]
38
+ payload = MultiJson.dump(filtered)
39
+ [name, "\n", payload.bytesize, payload].pack('a*a*l>a*')
40
+ end
41
+
42
+ class << self
43
+ def ok
44
+ %w(OK)
45
+ end
46
+
47
+ def error
48
+ %w(E_INVALID E_BAD_BODY)
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,39 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+ class Command
5
+ # Publish multiple messages
6
+ class Mpub < Command
7
+
8
+ # @!group Attributes
9
+
10
+ # @!macro [attach] attribute
11
+ # @!method $1
12
+ # @return [$2] the $1 $0
13
+ # @!method $1?
14
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
15
+ attribute :topic_name, String, :required => true
16
+ attribute :messages, Array, :required => true
17
+
18
+ # @!endgroup
19
+ def to_line
20
+ formatted_messages = messages.map do |message|
21
+ message = message.to_s
22
+ [message.bytesize, message].pack('l>a*')
23
+ end.join
24
+ [name, ' ', topic_name, "\n", formatted_messages.bytesize, messages.size, formatted_messages].pack('a*a*a*a*l>l>a*')
25
+ end
26
+
27
+ class << self
28
+ def ok
29
+ %w(OK)
30
+ end
31
+
32
+ def error
33
+ %w(E_INVALID E_BAD_TOPIC E_BAD_BODY E_BAD_MESSAGE E_MPUB_FAILED)
34
+ end
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,14 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+ class Command
5
+ # No-op
6
+ class Nop < Command
7
+
8
+ def to_line
9
+ "#{name}\n"
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,37 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+ class Command
5
+ # Publish single message
6
+ class Pub < Command
7
+
8
+ # @!group Attributes
9
+
10
+ # @!macro [attach] attribute
11
+ # @!method $1
12
+ # @return [$2] the $1 $0
13
+ # @!method $1?
14
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
15
+ attribute :topic_name, String, :required => true
16
+ attribute :message, Object, :required => true
17
+
18
+ # @!endgroup
19
+
20
+ def to_line
21
+ msg = message.to_s
22
+ [name, ' ', topic_name, "\n", msg.bytesize, msg].pack('a*a*a*a*l>a*')
23
+ end
24
+
25
+ class << self
26
+ def ok
27
+ %w(OK)
28
+ end
29
+
30
+ def error
31
+ %w(E_INVALID E_BAD_TOPIC E_BAD_MESSAGE E_PUB_FAILED)
32
+ end
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,31 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+ class Command
5
+ # Update RDY state
6
+ class Rdy < Command
7
+
8
+ # @!group Attributes
9
+
10
+ # @!macro [attach] attribute
11
+ # @!method $1
12
+ # @return [$2] the $1 $0
13
+ # @!method $1?
14
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
15
+ attribute :count, Integer, :required => true
16
+
17
+ # @!endgroup
18
+
19
+ def to_line
20
+ "#{name} #{count}\n"
21
+ end
22
+
23
+ class << self
24
+ def error
25
+ %w(E_INVALID)
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,32 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+ class Command
5
+ # Re-queue a message
6
+ class Req < Command
7
+
8
+ # @!group Attributes
9
+
10
+ # @!macro [attach] attribute
11
+ # @!method $1
12
+ # @return [$2] the $1 $0
13
+ # @!method $1?
14
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
15
+ attribute :message_id, String, :required => true
16
+ attribute :timeout, Integer, :required => true
17
+
18
+ # @!endgroup
19
+
20
+ def to_line
21
+ "#{name} #{message_id} #{self.timeout}\n"
22
+ end
23
+
24
+ class << self
25
+ def error
26
+ %w(E_INVALID E_REQ_FAILED)
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,36 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+ class Command
5
+ # Subscribe to topic/channel
6
+ class Sub < Command
7
+
8
+ # @!group Attributes
9
+
10
+ # @!macro [attach] attribute
11
+ # @!method $1
12
+ # @return [$2] the $1 $0
13
+ # @!method $1?
14
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
15
+ attribute :topic_name, String, :required => true
16
+ attribute :channel_name, String, :required => true
17
+
18
+ # @!endgroup
19
+
20
+ def to_line
21
+ "#{name} #{topic_name} #{channel_name}\n"
22
+ end
23
+
24
+ class << self
25
+ def ok
26
+ %w(OK)
27
+ end
28
+
29
+ def error
30
+ %w(E_INVALID E_BAD_TOPIC E_BAD_CHANNEL)
31
+ end
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,31 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+ class Command
5
+ # Reset timeout for in-flight message
6
+ class Touch < Command
7
+
8
+ # @!group Attributes
9
+
10
+ # @!macro [attach] attribute
11
+ # @!method $1
12
+ # @return [$2] the $1 $0
13
+ # @!method $1?
14
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
15
+ attribute :message_id, String, :required => true
16
+
17
+ # @!endgroup
18
+
19
+ def to_line
20
+ "#{name} #{message_id}\n"
21
+ end
22
+
23
+ class << self
24
+ def error
25
+ %w(E_INVALID E_TOUCH_FAILED)
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,417 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+
5
+ # Provides TCP connection to NSQD
6
+ class Connection
7
+
8
+ # Generate identifier for connection
9
+ #
10
+ # @param host [String]
11
+ # @param port [String, Integer]
12
+ # @param topic [String]
13
+ # @param channel [String]
14
+ # @return [String]
15
+ def self.identifier(host, port, topic, channel)
16
+ [host, port, topic, channel].compact.join('__')
17
+ end
18
+
19
+ include Utils::Lazy
20
+ # @!parse include Krakow::Utils::Lazy::InstanceMethods
21
+ # @!parse extend Krakow::Utils::Lazy::ClassMethods
22
+
23
+ include Celluloid
24
+
25
+ # Available connection features
26
+ FEATURES = [
27
+ :max_rdy_count,
28
+ :max_msg_timeout,
29
+ :msg_timeout,
30
+ :tls_v1,
31
+ :deflate,
32
+ :deflate_level,
33
+ :max_deflate_level,
34
+ :snappy,
35
+ :sample_rate,
36
+ :auth_required
37
+ ]
38
+
39
+ # List of features that may not be enabled together
40
+ EXCLUSIVE_FEATURES = [[:snappy, :deflate]]
41
+
42
+ # List of features that may be enabled by the client
43
+ ENABLEABLE_FEATURES = [:tls_v1, :snappy, :deflate, :auth_required]
44
+
45
+ finalizer :connection_cleanup
46
+
47
+ # @return [Hash] current configuration for endpoint
48
+ attr_reader :endpoint_settings
49
+ # @return [Ksocket] underlying socket like instance
50
+ attr_reader :socket
51
+ # @return [TrueClass, FalseClass]
52
+ attr_reader :running
53
+
54
+ # @!group Attributes
55
+
56
+ # @!macro [attach] attribute
57
+ # @!method $1
58
+ # @return [$2] the $1 $0
59
+ # @!method $1?
60
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
61
+ attribute :host, String, :required => true
62
+ attribute :port, [String,Integer], :required => true
63
+ attribute :topic, String
64
+ attribute :channel, String
65
+ attribute :version, String, :default => 'v2'
66
+ attribute :queue, [Queue, Consumer::Queue], :default => ->{ Queue.new }
67
+ attribute :callbacks, Hash, :default => ->{ Hash.new }
68
+ attribute :responses, Queue, :default => ->{ Queue.new }
69
+ attribute :notifier, [Celluloid::Signals, Celluloid::Condition, Celluloid::Actor]
70
+ attribute :features, Hash, :default => ->{ Hash.new }
71
+ attribute :response_wait, Numeric, :default => 1.0
72
+ attribute :response_interval, Numeric, :default => 0.03
73
+ attribute :error_wait, Numeric, :default => 0
74
+ attribute :enforce_features, [TrueClass,FalseClass], :default => true
75
+ attribute :features_args, Hash, :default => ->{ Hash.new }
76
+
77
+ # @!endgroup
78
+
79
+ # Create new instance
80
+ #
81
+ # @param args [Hash]
82
+ # @option args [String] :host (required) server host
83
+ # @option args [String, Numeric] :port (required) server port
84
+ # @option args [String] :version
85
+ # @option args [Queue] :queue received message queue
86
+ # @option args [Hash] :callbacks
87
+ # @option args [Queue] :responses received responses queue
88
+ # @option args [Celluloid::Actor] :notifier actor to notify on new message
89
+ # @option args [Hash] :features features to enable
90
+ # @option args [Numeric] :response_wait time to wait for response
91
+ # @option args [Numeric] :response_interval sleep interval for wait loop
92
+ # @option args [Numeric] :error_wait time to wait for error response
93
+ # @option args [TrueClass, FalseClass] :enforce_features fail if features are unavailable
94
+ # @option args [Hash] :feature_args options for connection features
95
+ def initialize(args={})
96
+ super
97
+ @endpoint_settings = {}
98
+ @running = false
99
+ end
100
+
101
+ # @return [String] identifier for this connection
102
+ def identifier
103
+ self.class.identifier(host, port, topic, channel)
104
+ end
105
+
106
+ # @return [String] stringify object
107
+ def to_s
108
+ "<#{self.class.name}:#{object_id} {#{host}:#{port}}>"
109
+ end
110
+
111
+ # Initialize the connection
112
+ #
113
+ # @return [nil]
114
+ def init!
115
+ connect!
116
+ async.process_to_queue!
117
+ nil
118
+ end
119
+
120
+ # Send message to remote server
121
+ #
122
+ # @param message [Krakow::Message] message to send
123
+ # @return [TrueClass, Krakow::FrameType] response if expected or true
124
+ def transmit(message)
125
+ unless(message.respond_to?(:to_line))
126
+ abort TypeError.new("Expecting type `Krakow::FrameType` but received `#{message.class}`")
127
+ end
128
+ output = message.to_line
129
+ response_wait = wait_time_for(message)
130
+ if(response_wait > 0)
131
+ transmit_with_response(message, response_wait)
132
+ else
133
+ debug ">>> #{output}"
134
+ socket.put(output)
135
+ true
136
+ end
137
+ end
138
+
139
+ # Sends message and waits for response
140
+ #
141
+ # @param message [Krakow::Message] message to send
142
+ # @return [Krakow::FrameType] response
143
+ def transmit_with_response(message, wait_time)
144
+ responses.clear
145
+ socket.put(message.to_line)
146
+ response = nil
147
+ (wait_time / response_interval).to_i.times do |i|
148
+ response = responses.pop unless responses.empty?
149
+ break if response
150
+ sleep(response_interval)
151
+ end
152
+ if(response)
153
+ message.response = response
154
+ if(message.error?(response))
155
+ res = Error::BadResponse.new "Message transmission failed #{message}"
156
+ res.result = response
157
+ abort res
158
+ end
159
+ response
160
+ else
161
+ unless(Command.response_for(message) == :error_only)
162
+ abort Error::BadResponse::NoResponse.new "No response provided for message #{message}"
163
+ end
164
+ end
165
+ end
166
+
167
+ # Destructor method for cleanup
168
+ #
169
+ # @return [nil]
170
+ def connection_cleanup
171
+ debug 'Tearing down connection'
172
+ @running = false
173
+ if(connected?)
174
+ socket.terminate
175
+ end
176
+ @socket = nil
177
+ info 'Connection torn down'
178
+ nil
179
+ end
180
+
181
+ # Receive from server
182
+ #
183
+ # @return [Krakow::FrameType, nil] message or nothing if read was empty
184
+ # @raise [Error::ConnectionUnavailable] socket is closed
185
+ def receive
186
+ debug 'Read wait for frame start'
187
+ buf = socket.get(8)
188
+ if(buf)
189
+ @receiving = true
190
+ debug "<<< #{buf.inspect}"
191
+ struct = FrameType.decode(buf)
192
+ debug "Decoded structure: #{struct.inspect}"
193
+ struct[:data] = socket.get(struct[:size])
194
+ debug "<<< #{struct[:data].inspect}"
195
+ @receiving = false
196
+ frame = FrameType.build(struct)
197
+ debug "Struct: #{struct.inspect} Frame: #{frame.inspect}"
198
+ frame
199
+ else
200
+ nil
201
+ end
202
+ end
203
+
204
+ # @return [TrueClass, FalseClass] is connection currently receiving a message
205
+ def receiving?
206
+ !!@receiving
207
+ end
208
+
209
+ # Receive messages and place into queue
210
+ #
211
+ # @return [nil]
212
+ def process_to_queue!
213
+ unless(@running)
214
+ @running = true
215
+ while(@running)
216
+ message = handle(receive)
217
+ if(message)
218
+ debug "Adding message to queue #{message}"
219
+ queue << message
220
+ if(notifier)
221
+ warn "Sending new message notification: #{notifier} - #{message}"
222
+ notifier.broadcast(message)
223
+ end
224
+ else
225
+ debug 'Received `nil` message. Ignoring.'
226
+ end
227
+ end
228
+ end
229
+ nil
230
+ end
231
+
232
+ # Handle non-message type Krakow::FrameType
233
+ #
234
+ # @param message [Krakow::FrameType] received message
235
+ # @return [Krakow::FrameType, nil]
236
+ def handle(message)
237
+ # Grab heartbeats upfront
238
+ if(message.is_a?(FrameType::Response) && message.response == '_heartbeat_')
239
+ debug 'Responding to heartbeat'
240
+ transmit Command::Nop.new
241
+ nil
242
+ else
243
+ message = callback_for(:handle, message)
244
+ if(!message.is_a?(FrameType::Message))
245
+ debug "Captured non-message type response: #{message}"
246
+ responses << message
247
+ nil
248
+ else
249
+ message
250
+ end
251
+ end
252
+ end
253
+
254
+ # Execute callback for given type
255
+ #
256
+ # @overload callback_for(type, arg, connection)
257
+ # @param type [Symbol] type of callback
258
+ # @param arg [Object] argument for callback (can be multiple)
259
+ # @param connection [Krakow::Connection] current connection
260
+ # @return [Object] result of callback
261
+ def callback_for(type, *args)
262
+ callback = callbacks[type]
263
+ if(callback)
264
+ debug "Processing connection callback for #{type.inspect} (#{callback.inspect})"
265
+ if(callback[:actor].alive?)
266
+ callback[:actor].send(callback[:method], *(args + [current_actor]))
267
+ else
268
+ error "Expected actor for callback processing is not alive! (type: `#{type.inspect}`)"
269
+ end
270
+ else
271
+ debug "No connection callback defined for #{type.inspect}"
272
+ args.size == 1 ? args.first : args
273
+ end
274
+ end
275
+
276
+ # Returns configured wait time for given message type
277
+ #
278
+ # @param message [Krakow::Command]
279
+ # @return [Numeric] seconds to wait
280
+ def wait_time_for(message)
281
+ case Command.response_for(message)
282
+ when :required
283
+ response_wait
284
+ when :error_only
285
+ error_wait
286
+ else
287
+ 0
288
+ end
289
+ end
290
+
291
+ # @return [Hash] default settings for IDENTIFY
292
+ def identify_defaults
293
+ unless(@identify_defaults)
294
+ @identify_defaults = {
295
+ :short_id => Socket.gethostname,
296
+ :long_id => Socket.gethostbyname(Socket.gethostname).flatten.compact.first,
297
+ :user_agent => "krakow/#{Krakow::VERSION}",
298
+ :feature_negotiation => true
299
+ }
300
+ end
301
+ @identify_defaults
302
+ end
303
+
304
+ # IDENTIFY with server and negotiate features
305
+ #
306
+ # @return [TrueClass]
307
+ def identify_and_negotiate
308
+ expected_features = identify_defaults.merge(features)
309
+ ident = Command::Identify.new(
310
+ expected_features
311
+ )
312
+ socket.put(ident.to_line)
313
+ response = receive
314
+ if(expected_features[:feature_negotiation])
315
+ begin
316
+ @endpoint_settings = MultiJson.load(response.content, :symbolize_keys => true)
317
+ info "Connection settings: #{endpoint_settings.inspect}"
318
+ # Enable things we need to enable
319
+ ENABLEABLE_FEATURES.each do |key|
320
+ if(endpoint_settings[key])
321
+ send(key)
322
+ elsif(enforce_features && expected_features[key])
323
+ abort Error::ConnectionFeatureFailure.new("Failed to enable #{key} feature on connection!")
324
+ end
325
+ end
326
+ rescue MultiJson::LoadError => e
327
+ error "Failed to parse response from Identify request: #{e} - #{response}"
328
+ abort e
329
+ end
330
+ else
331
+ @endpoint_settings = {}
332
+ end
333
+ true
334
+ end
335
+
336
+ # Send authentication request for connection
337
+ #
338
+ # @return [TrueClass]
339
+ def auth_required
340
+ info 'Authentication required for this connection'
341
+ if(feature_args[:auth])
342
+ transmit(Command::Auth.new(:secret => feature_args[:auth]))
343
+ response = receive
344
+ true
345
+ else
346
+ error 'No authentication information provided for connection!'
347
+ abort 'Authentication failure. No authentication secret provided'
348
+ end
349
+ end
350
+
351
+ # Enable snappy feature on underlying socket
352
+ #
353
+ # @return [TrueClass]
354
+ def snappy
355
+ info 'Loading support for snappy compression and converting connection'
356
+ @socket = ConnectionFeatures::SnappyFrames::Io.new(socket, features_args)
357
+ response = receive
358
+ info "Snappy connection conversion complete. Response: #{response.inspect}"
359
+ true
360
+ end
361
+
362
+ # Enable deflate feature on underlying socket
363
+ #
364
+ # @return [TrueClass]
365
+ def deflate
366
+ debug 'Loading support for deflate compression and converting connection'
367
+ @socket = ConnectionFeatures::Deflate::Io.new(socket, features_args)
368
+ response = receive
369
+ info "Deflate connection conversion complete. Response: #{response.inspect}"
370
+ true
371
+ end
372
+
373
+ # Enable TLS feature on underlying socket
374
+ #
375
+ # @return [TrueClass]
376
+ def tls_v1
377
+ info 'Enabling TLS for connection'
378
+ @socket = ConnectionFeatures::Ssl::Io.new(socket, features_args)
379
+ response = receive
380
+ info "TLS enable complete. Response: #{response.inspect}"
381
+ true
382
+ end
383
+
384
+ # @return [TrueClass, FalseClass] underlying socket is connected
385
+ def connected?
386
+ begin
387
+ !!(socket && socket.alive?)
388
+ rescue Celluloid::DeadActorError
389
+ false
390
+ end
391
+ end
392
+
393
+ protected
394
+
395
+ # Connect the underlying socket
396
+ #
397
+ # @return [nil]
398
+ def connect!
399
+ debug 'Initializing connection'
400
+ unless(@connecting)
401
+ @connecting = true
402
+ if(socket && socket.alive?)
403
+ socket.terminate
404
+ @socket = nil
405
+ end
406
+ @socket = Ksocket.new(:host => host, :port => port)
407
+ self.link socket
408
+ socket.put version.rjust(4).upcase
409
+ identify_and_negotiate
410
+ info 'Connection initialized'
411
+ @connecting = false
412
+ end
413
+ nil
414
+ end
415
+
416
+ end
417
+ end