krakow 0.0.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.
data/CHANGELOG.md ADDED
@@ -0,0 +1,2 @@
1
+ ## v0.0.1
2
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,28 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ krakow (0.1.0)
5
+ celluloid-io
6
+ http
7
+ multi_json
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ celluloid (0.15.2)
13
+ timers (~> 1.1.0)
14
+ celluloid-io (0.15.0)
15
+ celluloid (>= 0.15.0)
16
+ nio4r (>= 0.5.0)
17
+ http (0.5.0)
18
+ http_parser.rb
19
+ http_parser.rb (0.6.0)
20
+ multi_json (1.8.4)
21
+ nio4r (0.5.0)
22
+ timers (1.1.0)
23
+
24
+ PLATFORMS
25
+ ruby
26
+
27
+ DEPENDENCIES
28
+ krakow!
data/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # Krakow
2
+
3
+ "KRAKOW! KRAKOW! Two direct hits!"
4
+
5
+ ## Spiff
6
+
7
+ ```ruby
8
+ require 'krakow'
9
+
10
+ producer = Krakow::Producer(
11
+ :host => 'HOST',
12
+ :port => 'PORT',
13
+ :topic => 'target'
14
+ )
15
+ producer.write('direct hit!')
16
+ ```
17
+
18
+ ## Zargons
19
+
20
+ ```ruby
21
+ require 'krakow'
22
+
23
+ consumer = Krakow::Consumer(
24
+ :nsqlookupd => 'http://HOST:PORT',
25
+ :topic => 'target',
26
+ :channel => 'ship'
27
+ )
28
+
29
+ message = consumer.queue.pop
30
+ # do stuff
31
+ consumer.confirm(message.message_id)
32
+ ```
33
+
34
+ # Info
35
+ * Repo: https://github.com/chrisroberts/krakow
36
+ * IRC: Freenode @ spox
data/krakow.gemspec ADDED
@@ -0,0 +1,16 @@
1
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__)) + '/lib/'
2
+ require 'krakow/version'
3
+ Gem::Specification.new do |s|
4
+ s.name = 'krakow'
5
+ s.version = Krakow::VERSION.version
6
+ s.summary = 'NSQ library'
7
+ s.author = 'Chris Roberts'
8
+ s.email = 'code@chrisroberts.org'
9
+ s.homepage = 'http://github.com/chrisroberts/krakow'
10
+ s.description = 'NSQ ruby library'
11
+ s.require_path = 'lib'
12
+ s.add_dependency 'celluloid-io'
13
+ s.add_dependency 'http'
14
+ s.add_dependency 'multi_json'
15
+ s.files = Dir['**/*']
16
+ end
@@ -0,0 +1,15 @@
1
+ module Krakow
2
+ class Command
3
+ class Cls < Command
4
+
5
+ def initialize(args={})
6
+ super
7
+ end
8
+
9
+ def to_line
10
+ "#{name}\n"
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ module Krakow
2
+ class Command
3
+ class Fin < Command
4
+
5
+ def initialize(args={})
6
+ super
7
+ required! :message_id
8
+ end
9
+
10
+ def to_line
11
+ "#{name} #{message_id}\n"
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,24 @@
1
+ require 'multi_json'
2
+
3
+ module Krakow
4
+ class Command
5
+ class Identify < Command
6
+
7
+ def initialize(args={})
8
+ super
9
+ required! :short_id, :long_id
10
+ optional(
11
+ :feature_negotiation, :heartbeat_interval, :output_buffer_size,
12
+ :output_buffer_timeout, :tls_v1, :snappy, :deflate, :deflate_level,
13
+ :sample_rate
14
+ )
15
+ end
16
+
17
+ def to_line
18
+ payload = MultiJson.dump(arguments)
19
+ [name, "\n", payload.length, payload].pack('a*a*l>a*')
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ module Krakow
2
+ class Command
3
+ class Mpub < Command
4
+
5
+ def initialize(args={})
6
+ super
7
+ required! :topic_name, :messages
8
+ end
9
+
10
+ def to_line
11
+ formatted_messages = messages.map do |message|
12
+ [message.length, message].pack('l>a*')
13
+ end.join
14
+ [name, ' ', topic_name, "\n", formatted_messages.length, messages.size, formatted_messages].pack('a*a*a*a*l>l>a*')
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ module Krakow
2
+ class Command
3
+ class Nop < Command
4
+
5
+ def initialize(args={})
6
+ super
7
+ end
8
+
9
+ def to_line
10
+ "#{name}\n"
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+
2
+ module Krakow
3
+ class Command
4
+ class Pub < Command
5
+
6
+ def initialize(args={})
7
+ super
8
+ required! :topic_name, :message
9
+ end
10
+
11
+ def to_line
12
+ [name, ' ', topic_name, "\n", message.length, message].pack('a*a*a*a*l>a*')
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ module Krakow
2
+ class Command
3
+ class Rdy < Command
4
+
5
+ def initialize(args={})
6
+ super
7
+ required! :count
8
+ end
9
+
10
+ def to_line
11
+ "#{name} #{count}\n"
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Krakow
2
+ class Command
3
+ class Req < Command
4
+
5
+ def initialize(args={})
6
+ super
7
+ required! :message_id, :timeout
8
+ end
9
+
10
+ def to_line
11
+ "#{name} #{message_id} #{timeout}\n"
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Krakow
2
+ class Command
3
+ class Sub < Command
4
+
5
+ def initialize(args={})
6
+ super
7
+ required! :topic_name, :channel_name
8
+ end
9
+
10
+ def to_line
11
+ "#{name} #{topic_name} #{channel_name}\n"
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Krakow
2
+ class Command
3
+ class Touch < Command
4
+
5
+ def initialize(args={})
6
+ super
7
+ required! :message_id
8
+ end
9
+
10
+ def to_line
11
+ "#{name} #{message_id}\n"
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,25 @@
1
+ module Krakow
2
+ class Command
3
+
4
+ include Utils::Lazy
5
+
6
+ # Return command name
7
+ def name
8
+ self.class.name.split('::').last.upcase
9
+ end
10
+
11
+ # Convert to line output
12
+ def to_line
13
+ raise NoMethodError.new 'No line conversion method defined!'
14
+ end
15
+
16
+ # Make all the commands available
17
+ Dir.glob(File.join(File.dirname(__FILE__), 'command', '*')).each do |path|
18
+ autoload(
19
+ File.basename(path).sub(File.extname(path), '').capitalize.to_sym,
20
+ File.join('krakow/command', File.basename(path).sub(File.extname(path), ''))
21
+ )
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,89 @@
1
+ require 'celluloid/io'
2
+ require 'celluloid/autostart'
3
+
4
+ module Krakow
5
+ class Connection
6
+
7
+ include Utils::Lazy
8
+ include Celluloid::IO
9
+
10
+ finalizer :goodbye_my_love!
11
+
12
+ attr_reader :socket
13
+
14
+ def initialize(args={})
15
+ super
16
+ required! :host, :port
17
+ optional :version, :queue, :callback
18
+ arguments[:queue] ||= Queue.new
19
+ arguments[:version] ||= 'v2'
20
+ @socket = TCPSocket.new(host, port)
21
+ end
22
+
23
+ # Initialize the connection
24
+ def init!
25
+ socket.write version.rjust(4).upcase
26
+ async.process_to_queue!
27
+ end
28
+
29
+ # message:: Command instance to send
30
+ # Send the message
31
+ def transmit(message)
32
+ socket.write message.to_line
33
+ end
34
+
35
+ # Cleanup prior to destruction
36
+ def goodbye_my_love!
37
+ if(socket && !socket.closed?)
38
+ socket.write Command::Cls.new.to_line
39
+ socket.close
40
+ end
41
+ @socket = nil
42
+ end
43
+
44
+ # Receive message and return proper FrameType instance
45
+ def receive
46
+ buf = socket.read(8)
47
+ if(buf)
48
+ @receiving = true
49
+ struct = FrameType.decode(buf)
50
+ struct[:data] = socket.read(struct[:size])
51
+ @receiving = false
52
+ FrameType.build(struct)
53
+ else
54
+ nil
55
+ end
56
+ end
57
+
58
+ # Currently in the process of receiving a message
59
+ def receiving?
60
+ !!@receiving
61
+ end
62
+
63
+ # Pull message and queue
64
+ def process_to_queue!
65
+ loop do
66
+ message = handle(receive)
67
+ if(message)
68
+ queue << message
69
+ end
70
+ end
71
+ end
72
+
73
+ # message:: FrameType instance
74
+ # Handle message if not an actual message
75
+ def handle(message)
76
+ # Grab heartbeats upfront
77
+ if(message.is_a?(FrameType::Response) && message.response == '_heartbeat_')
78
+ socket.write Command::Nop.new.to_line
79
+ nil
80
+ else
81
+ if(callback && callback[:actor] && callback[:method])
82
+ callback[:actor].send(callback[:method], message, current_actor)
83
+ else
84
+ message
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,101 @@
1
+ module Krakow
2
+ class Consumer
3
+
4
+ include Utils::Lazy
5
+ include Celluloid
6
+
7
+ finalizer :goodbye_my_love!
8
+
9
+ attr_reader :connections, :discovery, :queue
10
+
11
+ def initialize(args={})
12
+ super
13
+ required! :topic, :channel
14
+ optional :host, :port, :nslookupd, :receive_count
15
+ @connections = {}
16
+ @queue = Queue.new
17
+ if(nslookupd)
18
+ @discovery = Discovery.new(:nslookupd => nslookupd)
19
+ every(60){ init! }
20
+ init!
21
+ else
22
+ connection = build_connection(host, port, queue)
23
+ if(register(connection))
24
+ connections[:default] = connection
25
+ else
26
+ raise Error.new("Failed to establish subscription at provided end point (#{host}:#{port}")
27
+ end
28
+ end
29
+ end
30
+
31
+ def goodbye_my_love!
32
+ connections.values.each do |con|
33
+ con.terminate
34
+ end
35
+ end
36
+
37
+ def build_connection(host, port, queue)
38
+ connection = Connection.new(
39
+ :host => host,
40
+ :port => port,
41
+ :queue => queue
42
+ )
43
+ end
44
+
45
+ def process_message(message, connection)
46
+ puts 'PROCESSING!'
47
+ if(message.is_a?(FrameType::Message))
48
+ connection.transmit(Command::Rdy.new(:count => receive_count || 1))
49
+ end
50
+ message
51
+ end
52
+
53
+ # Requests lookup and adds connections
54
+ def init!
55
+ found = discovery.lookup(topic)
56
+ found.each do |node|
57
+ unless(connections[node[:hostname]])
58
+ connection = build_connection(node[:broadcast_address], node[:tcp_port], queue)
59
+ connections[node[:hostname]] = connection if register(connection)
60
+ end
61
+ end
62
+ end
63
+
64
+ # connection:: Connection
65
+ # Registers connection with subscription. Returns false if failed
66
+ def register(connection)
67
+ connection.init!
68
+ connection.transmit(Command::Sub.new(:topic_name => topic, :channel_name => channel))
69
+ unless(connection.queue.pop.is_a?(FrameType::Error))
70
+ connection.transmit(Command::Rdy.new(:count => receive_count || 1))
71
+ true
72
+ else
73
+ connection.terminate
74
+ false
75
+ end
76
+ end
77
+
78
+ # message_id:: Message ID
79
+ # Confirm message has been processed
80
+ def confirm(message_id)
81
+ writer.transmit(Command::Fin.new(:message_id => message_id))
82
+ writer.transmit(Command::Rdy.new(:count => (receive_count - queue.size) + 1))
83
+ true
84
+ end
85
+
86
+ # message_id:: Message ID
87
+ # timeout:: Requeue timeout (default is none)
88
+ # Requeue message (processing failure)
89
+ def requeue(message_id, timeout=0)
90
+ writer.transmit(Command::Req.new(:message_id => message_id, :timeout => timeout))
91
+ end
92
+
93
+ # Attempt to return free connection from pool for writing
94
+ def writer
95
+ connections.values.detect do |con|
96
+ !con.receiving?
97
+ end || connections.values.first
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,41 @@
1
+ require 'uri'
2
+ require 'http'
3
+ require 'multi_json'
4
+
5
+ module Krakow
6
+ class Discovery
7
+
8
+ include Utils::Lazy
9
+
10
+ def initialize(args={})
11
+ super
12
+ required! :nslookupd
13
+ end
14
+
15
+ # topic:: Topic name
16
+ # Return list of end points with given topic name available
17
+ def lookup(topic)
18
+ [nslookupd].flatten.map do |location|
19
+ uri = URI.parse(location)
20
+ uri.path = '/lookup'
21
+ uri.query = "topic=#{topic}&ts=#{Time.now.to_i}"
22
+ begin
23
+ content = HTTP.with(:accept => 'application/octet-stream').get(uri.to_s)
24
+ unless(content.respond_to?(:to_hash))
25
+ data = MultiJson.load(content.to_s)
26
+ else
27
+ data = content.to_hash
28
+ end
29
+ if(data['data'] && data['data']['producers'])
30
+ data['data']['producers'].map do |producer|
31
+ Hash[*producer.map{|k,v| [k.to_sym, v]}.flatten]
32
+ end
33
+ end
34
+ rescue => e
35
+ nil
36
+ end
37
+ end.compact.flatten(1).uniq
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,9 @@
1
+ module Krakow
2
+ class Error < StandardError
3
+
4
+ class BadResponse < Error
5
+ attr_accessor :result
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ module Krakow
2
+ class FrameType
3
+ class Error < FrameType
4
+
5
+ def initialize(args={})
6
+ super
7
+ required! :error
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Krakow
2
+ class FrameType
3
+ class Message < FrameType
4
+
5
+ def initialize(args={})
6
+ super
7
+ required! :attempts, :timestamp, :message_id, :message
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Krakow
2
+ class FrameType
3
+ class Response < FrameType
4
+
5
+ def initialize(args={})
6
+ super
7
+ required! :response
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,50 @@
1
+ module Krakow
2
+ class FrameType
3
+
4
+ autoload :Error, 'krakow/frame_type/error'
5
+ autoload :Message, 'krakow/frame_type/message'
6
+ autoload :Response, 'krakow/frame_type/response'
7
+
8
+ include Utils::Lazy
9
+
10
+ FRAME_TYPE_MAP = [
11
+ FrameType::Response,
12
+ FrameType::Error,
13
+ FrameType::Message
14
+ ]
15
+ SIZE_BYTES = 4
16
+
17
+ class << self
18
+
19
+ # bytes:: 8 bytes
20
+ # Return information about incoming frame
21
+ def decode(bytes)
22
+ size, type = bytes.unpack('l>l>')
23
+ {:size => size - SIZE_BYTES, :type => type}
24
+ end
25
+
26
+ # args:: arguments (:type, :data, :size)
27
+ # Build proper FrameType instance based on args
28
+ def build(args={})
29
+ klass = FRAME_TYPE_MAP[args[:type].to_i]
30
+ if(klass == FrameType::Response)
31
+ klass.new(:response => args[:data])
32
+ elsif(klass == FrameType::Error)
33
+ klass.new(:error => args[:data])
34
+ elsif(klass == FrameType::Message)
35
+ unpacked = args[:data].unpack("Q>s>a16a#{args[:size]}")
36
+ klass.new(
37
+ Hash[*([:timestamp, :attempts, :message_id, :message].zip(unpacked).flatten)]
38
+ )
39
+ else
40
+ raise TypeError.new "Unknown frame type received: #{args[:type].inspect} - #{klass.inspect}"
41
+ end
42
+ end
43
+ end
44
+
45
+ def initialize(args={})
46
+ super
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,61 @@
1
+ module Krakow
2
+ class Producer
3
+
4
+ include Utils::Lazy
5
+ include Celluloid
6
+
7
+ finalizer :goodbye_my_love!
8
+
9
+ attr_reader :connection
10
+
11
+ def initialize(args={})
12
+ super
13
+ required! :host, :port, :topic
14
+ @connection = Connection.new(:host => host, :port => port)
15
+ connection.init!
16
+ end
17
+
18
+ def goodbye_my_love!
19
+ if(connection)
20
+ connection.terminate
21
+ end
22
+ @connection = nil
23
+ end
24
+
25
+ # message:: Message to send
26
+ # Write message
27
+ def write(*message)
28
+ if(message.size > 1)
29
+ connection.transmit(
30
+ Command::Mpub.new(
31
+ :topic_name => topic,
32
+ :messages => message
33
+ )
34
+ )
35
+ else
36
+ connection.transmit(
37
+ Command::Pub.new(
38
+ :message => message.first,
39
+ :topic_name => topic
40
+ )
41
+ )
42
+ end
43
+ read(:validate)
44
+ end
45
+
46
+ # args:: Options (:validate)
47
+ # Read response from connection. If :validate is included an
48
+ # exception will be raised if `FrameType::Error` is received
49
+ def read(*args)
50
+ result = connection.queue.pop
51
+ if(args.include?(:validate) && result.is_a?(FrameType::Error))
52
+ error = Error::BadResponse.new('Write failed')
53
+ error.result = result
54
+ abort error
55
+ else
56
+ result
57
+ end
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,52 @@
1
+ module Krakow
2
+ module Utils
3
+ module Lazy
4
+ attr_reader :arguments
5
+
6
+ def initialize(args={})
7
+ @arguments = {}.tap do |hash|
8
+ args.each do |k,v|
9
+ hash[k.to_sym] = v
10
+ end
11
+ end
12
+ end
13
+
14
+ # args:: list of required keys
15
+ # Check that required keys exist in `arguments` hash. Raise
16
+ # error if not found
17
+ def required!(*args)
18
+ args.each do |key|
19
+ unless(arguments.has_key?(key.to_sym))
20
+ raise ArgumentError.new "Missing required option `#{key}`!"
21
+ end
22
+ end
23
+ end
24
+
25
+ # args:: list of required keys
26
+ # Optional keys for arguments
27
+ def optional(*args)
28
+ args.each do |key|
29
+ key = key.to_sym
30
+ unless(arguments.has_key?(key))
31
+ arguments[key] = nil
32
+ end
33
+ end
34
+ end
35
+
36
+ def method_missing(*args)
37
+ key = args.first.to_sym
38
+ if(arguments.has_key?(key))
39
+ arguments[key]
40
+ else
41
+ super
42
+ end
43
+ end
44
+
45
+ def respond_to_missing?(key, *args)
46
+ key = key.to_sym
47
+ super || arguments.has_key?(key)
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,5 @@
1
+ module Krakow
2
+ module Utils
3
+ autoload :Lazy, 'krakow/utils/lazy'
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+ class Version < Gem::Version
5
+ end
6
+ VERSION = Version.new('0.0.1')
7
+ end
data/lib/krakow.rb ADDED
@@ -0,0 +1,15 @@
1
+ autoload :Celluloid, 'celluloid'
2
+
3
+ module Krakow
4
+
5
+ autoload :Command, 'krakow/command'
6
+ autoload :Connection, 'krakow/connection'
7
+ autoload :Consumer, 'krakow/consumer'
8
+ autoload :Discovery, 'krakow/discovery'
9
+ autoload :Error, 'krakow/exceptions'
10
+ autoload :FrameType, 'krakow/frame_type'
11
+ autoload :Producer, 'krakow/producer'
12
+ autoload :Utils, 'krakow/utils'
13
+ autoload :Version, 'krakow/version'
14
+
15
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: krakow
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Chris Roberts
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-01-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: celluloid-io
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: http
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: multi_json
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: NSQ ruby library
63
+ email: code@chrisroberts.org
64
+ executables: []
65
+ extensions: []
66
+ extra_rdoc_files: []
67
+ files:
68
+ - lib/krakow.rb
69
+ - lib/krakow/consumer.rb
70
+ - lib/krakow/frame_type.rb
71
+ - lib/krakow/command.rb
72
+ - lib/krakow/version.rb
73
+ - lib/krakow/utils/lazy.rb
74
+ - lib/krakow/producer.rb
75
+ - lib/krakow/frame_type/response.rb
76
+ - lib/krakow/frame_type/error.rb
77
+ - lib/krakow/frame_type/message.rb
78
+ - lib/krakow/command/pub.rb
79
+ - lib/krakow/command/cls.rb
80
+ - lib/krakow/command/touch.rb
81
+ - lib/krakow/command/fin.rb
82
+ - lib/krakow/command/identify.rb
83
+ - lib/krakow/command/req.rb
84
+ - lib/krakow/command/nop.rb
85
+ - lib/krakow/command/mpub.rb
86
+ - lib/krakow/command/sub.rb
87
+ - lib/krakow/command/rdy.rb
88
+ - lib/krakow/connection.rb
89
+ - lib/krakow/exceptions.rb
90
+ - lib/krakow/utils.rb
91
+ - lib/krakow/discovery.rb
92
+ - Gemfile
93
+ - README.md
94
+ - krakow.gemspec
95
+ - CHANGELOG.md
96
+ - Gemfile.lock
97
+ homepage: http://github.com/chrisroberts/krakow
98
+ licenses: []
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 1.8.24
118
+ signing_key:
119
+ specification_version: 3
120
+ summary: NSQ library
121
+ test_files: []
122
+ has_rdoc: