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,224 @@
1
+ require 'http'
2
+ require 'uri'
3
+ require 'ostruct'
4
+
5
+ require 'cgi'
6
+ # NOTE: Prevents weird "first" run behavior
7
+ begin
8
+ require 'json'
9
+ rescue LoadError
10
+ # ignore (maybe log?)
11
+ end
12
+
13
+ require 'krakow'
14
+
15
+ module Krakow
16
+ class Producer
17
+
18
+ # HTTP based producer
19
+ class Http
20
+
21
+ include Utils::Lazy
22
+ # @!parse include Krakow::Utils::Lazy::InstanceMethods
23
+ # @!parse extend Krakow::Utils::Lazy::ClassMethods
24
+
25
+ # Wrapper for HTTP response hash
26
+ class Response < OpenStruct
27
+ end
28
+
29
+ attr_reader :uri
30
+
31
+ # @!group Attributes
32
+
33
+ # @!macro [attach] attribute
34
+ # @!method $1
35
+ # @return [$2] the $1 $0
36
+ # @!method $1?
37
+ # @return [TrueClass, FalseClass] truthiness of the $1 $0
38
+ attribute :endpoint, String, :required => true
39
+ attribute :topic, String, :required => true
40
+ attribute :config, Hash, :default => ->{ Hash.new }
41
+ attribute :ssl_context, Hash
42
+
43
+ # @!endgroup
44
+
45
+ def initialize(args={})
46
+ super
47
+ build_ssl_context if ssl_context
48
+ @uri = URI.parse(endpoint)
49
+ end
50
+
51
+ # Create a new SSL context
52
+ #
53
+ # @return [OpenSSL::SSL::SSLContext]
54
+ def build_ssl_context
55
+ require 'openssl'
56
+ context = OpenSSL::SSL::SSLContext.new
57
+ context.cert = OpenSSL::X509::Certificate.new(File.open(ssl_context[:certificate]))
58
+ context.key = OpenSSL::PKey::RSA.new(File.open(ssl_context[:key]))
59
+ config[:ssl_context] = context
60
+ end
61
+
62
+ # Send a message via HTTP
63
+ #
64
+ # @param method [String, Symbol] HTTP method to use (:get, :put, etc)
65
+ # @param path [String] URI path
66
+ # @param args [Hash] payload hash
67
+ # @return [Response]
68
+ def send_message(method, path, args={})
69
+ build = uri.dup
70
+ build.path = "/#{path}"
71
+ response = HTTP.send(method, build.to_s, args.merge(config))
72
+ begin
73
+ response = MultiJson.load(response.body.to_s)
74
+ rescue MultiJson::LoadError
75
+ response = {
76
+ 'status_code' => response.code,
77
+ 'status_txt' => response.body.to_s,
78
+ 'response' => response.body.to_s,
79
+ 'data' => nil,
80
+ }
81
+ end
82
+ Response.new(response)
83
+ end
84
+
85
+ # Send messages
86
+ #
87
+ # @param payload [String] message
88
+ # @return [Response]
89
+ def write(*payload)
90
+ if(payload.size == 1)
91
+ payload = payload.first
92
+ send_message(:post, :pub,
93
+ :body => payload,
94
+ :params => {:topic => topic}
95
+ )
96
+ else
97
+ send_message(:post, :mpub,
98
+ :body => payload.join("\n"),
99
+ :params => {:topic => topic}
100
+ )
101
+ end
102
+ end
103
+
104
+ # Create the topic
105
+ #
106
+ # @return [Response]
107
+ def create_topic
108
+ send_message(:post, :create_topic,
109
+ :params => {:topic => topic}
110
+ )
111
+ end
112
+
113
+ # Delete the topic
114
+ #
115
+ # @return [Response]
116
+ def delete_topic
117
+ send_message(:post, :delete_topic,
118
+ :params => {:topic => topic}
119
+ )
120
+ end
121
+
122
+ # Create channel on topic
123
+ #
124
+ # @param chan [String] channel name
125
+ # @return [Response]
126
+ def create_channel(chan)
127
+ send_message(:post, :create_channel,
128
+ :params => {
129
+ :topic => topic,
130
+ :channel => chan
131
+ }
132
+ )
133
+ end
134
+
135
+ # Delete channel on topic
136
+ #
137
+ # @param chan [String] channel name
138
+ # @return [Response]
139
+ def delete_channel(chan)
140
+ send_message(:post, :delete_channel,
141
+ :params => {
142
+ :topic => topic,
143
+ :channel => chan
144
+ }
145
+ )
146
+ end
147
+
148
+ # Remove all messages from topic
149
+ #
150
+ # @return [Response]
151
+ def empty_topic
152
+ send_message(:post, :empty_topic,
153
+ :params => {:topic => topic}
154
+ )
155
+ end
156
+
157
+ # Remove all messages from given channel on topic
158
+ #
159
+ # @param chan [String] channel name
160
+ # @return [Response]
161
+ def empty_channel(chan)
162
+ send_message(:post, :empty_channel,
163
+ :params => {
164
+ :topic => topic,
165
+ :channel => chan
166
+ }
167
+ )
168
+ end
169
+
170
+ # Pause messages on given channel
171
+ #
172
+ # @param chan [String] channel name
173
+ # @return [Response]
174
+ def pause_channel(chan)
175
+ send_message(:post, :pause_channel,
176
+ :params => {
177
+ :topic => topic,
178
+ :channel => chan
179
+ }
180
+ )
181
+ end
182
+
183
+ # Resume messages on a given channel
184
+ #
185
+ # @param chan [String] channel name
186
+ # @return [Response]
187
+ def unpause_channel(chan)
188
+ send_message(:post, :unpause_channel,
189
+ :params => {
190
+ :topic => topic,
191
+ :channel => chan
192
+ }
193
+ )
194
+ end
195
+
196
+ # Server stats
197
+ #
198
+ # @param format [String] format of data
199
+ # @return [Response]
200
+ def stats(format='json')
201
+ send_message(:get, :stats,
202
+ :params => {
203
+ :format => format
204
+ }
205
+ )
206
+ end
207
+
208
+ # Ping the server
209
+ #
210
+ # @return [Response]
211
+ def ping
212
+ send_message(:get, :ping)
213
+ end
214
+
215
+ # Server information
216
+ #
217
+ # @return [Response]
218
+ def info
219
+ send_message(:get, :info)
220
+ end
221
+
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,9 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+ # Helper utilities
5
+ module Utils
6
+ autoload :Lazy, 'krakow/utils/lazy'
7
+ autoload :Logging, 'krakow/utils/logging'
8
+ end
9
+ end
@@ -0,0 +1,125 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+ module Utils
5
+ # Adds functionality to facilitate laziness
6
+ module Lazy
7
+
8
+ include Utils::Logging
9
+
10
+ # Instance methods for laziness
11
+ module InstanceMethods
12
+
13
+ # @return [Hash] argument hash
14
+ attr_reader :arguments
15
+
16
+ # Create new instance
17
+ #
18
+ # @param args [Hash]
19
+ # @return [Object]
20
+ def initialize(args={})
21
+ @arguments = {}.tap do |hash|
22
+ self.class.attributes.each do |name, options|
23
+ val = args[name]
24
+ if(options[:required] && !args.has_key?(name))
25
+ raise ArgumentError.new("Missing required option: `#{name}`")
26
+ end
27
+ if(val && options[:type] && !(valid = [options[:type]].flatten.compact).detect{|k| val.is_a?(k)})
28
+ raise TypeError.new("Invalid type for option `#{name}` (#{val} <#{val.class}>). Valid - #{valid.map(&:to_s).join(',')}")
29
+ end
30
+ if(val.nil? && options[:default] && !args.has_key?(name))
31
+ val = options[:default].respond_to?(:call) ? options[:default].call : options[:default]
32
+ end
33
+ hash[name] = val
34
+ end
35
+ end
36
+ end
37
+ alias_method :super_init, :initialize
38
+
39
+ # @return [String]
40
+ def to_s
41
+ "<#{self.class.name}:#{object_id}>"
42
+ end
43
+
44
+ # @return [String]
45
+ def inspect
46
+ "<#{self.class.name}:#{object_id} [#{arguments.inspect}]>"
47
+ end
48
+
49
+ end
50
+
51
+ # Class methods for laziness
52
+ module ClassMethods
53
+
54
+ # Add new attributes to class
55
+ #
56
+ # @param name [String]
57
+ # @param type [Class, Array<Class>]
58
+ # @param options [Hash]
59
+ # @option options [true, false] :required must be provided on initialization
60
+ # @option options [Object, Proc] :default default value
61
+ # @return [nil]
62
+ def attribute(name, type, options={})
63
+ name = name.to_sym
64
+ attributes[name] = {:type => type}.merge(options)
65
+ define_method(name) do
66
+ arguments[name.to_sym]
67
+ end
68
+ define_method("#{name}?") do
69
+ !!arguments[name.to_sym]
70
+ end
71
+ nil
72
+ end
73
+
74
+ # Return attributes
75
+ #
76
+ # @param args [Symbol] :required or :optional
77
+ # @return [Array<Hash>]
78
+ def attributes(*args)
79
+ @attributes ||= {}
80
+ if(args.include?(:required))
81
+ Hash[@attributes.find_all{|k,v| v[:required]}]
82
+ elsif(args.include?(:optional))
83
+ Hash[@attributes.find_all{|k,v| !v[:required]}]
84
+ else
85
+ @attributes
86
+ end
87
+ end
88
+
89
+ # Directly set attribute hash
90
+ #
91
+ # @param attrs [Hash]
92
+ # @return [TrueClass]
93
+ # @todo need deep dup here
94
+ def set_attributes(attrs)
95
+ @attributes = attrs.dup
96
+ true
97
+ end
98
+
99
+ end
100
+
101
+ class << self
102
+
103
+ # Injects laziness into class
104
+ #
105
+ # @param klass [Class]
106
+ def included(klass)
107
+ klass.class_eval do
108
+ include InstanceMethods
109
+ extend ClassMethods
110
+
111
+ class << self
112
+
113
+ def inherited(klass)
114
+ klass.set_attributes(self.attributes)
115
+ end
116
+
117
+ end
118
+ end
119
+ end
120
+
121
+ end
122
+
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,43 @@
1
+ require 'krakow'
2
+
3
+ module Krakow
4
+ module Utils
5
+ # Logging helpers
6
+ module Logging
7
+
8
+ # Define base logging types
9
+ %w(debug info warn error).each do |key|
10
+ define_method(key) do |string|
11
+ log(key, string)
12
+ end
13
+ end
14
+
15
+ # Log message
16
+ #
17
+ # @param args [Array, nil]
18
+ # @return [Logger, nil]
19
+ def log(*args)
20
+ if(args.empty?)
21
+ Celluloid::Logger
22
+ else
23
+ severity, string = args
24
+ Celluloid::Logger.send(severity.to_sym, "#{self}: #{string}")
25
+ nil
26
+ end
27
+ end
28
+
29
+ class << self
30
+ # Set the logging output level
31
+ #
32
+ # @param level [Integer]
33
+ # @return [Integer, nil]
34
+ def level=(level)
35
+ if(Celluloid.logger.class == Logger)
36
+ Celluloid.logger.level = Logger.const_get(level.to_s.upcase.to_sym)
37
+ end
38
+ end
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,4 @@
1
+ module Krakow
2
+ # Current version
3
+ VERSION = Gem::Version.new('0.1.0')
4
+ end
metadata ADDED
@@ -0,0 +1,184 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nsq-krakow
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Chris Roberts
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-06-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: celluloid
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.16.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.16.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: http
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: multi_json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: digest-crc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: childprocess
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: snappy
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: NSQ ruby library
112
+ email: code@chrisroberts.org
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files:
116
+ - CHANGELOG.md
117
+ - CONTRIBUTING.md
118
+ - LICENSE
119
+ files:
120
+ - CHANGELOG.md
121
+ - CONTRIBUTING.md
122
+ - LICENSE
123
+ - README.md
124
+ - krakow.gemspec
125
+ - lib/krakow.rb
126
+ - lib/krakow/command.rb
127
+ - lib/krakow/command/auth.rb
128
+ - lib/krakow/command/cls.rb
129
+ - lib/krakow/command/fin.rb
130
+ - lib/krakow/command/identify.rb
131
+ - lib/krakow/command/mpub.rb
132
+ - lib/krakow/command/nop.rb
133
+ - lib/krakow/command/pub.rb
134
+ - lib/krakow/command/rdy.rb
135
+ - lib/krakow/command/req.rb
136
+ - lib/krakow/command/sub.rb
137
+ - lib/krakow/command/touch.rb
138
+ - lib/krakow/connection.rb
139
+ - lib/krakow/connection_features.rb
140
+ - lib/krakow/connection_features/deflate.rb
141
+ - lib/krakow/connection_features/snappy_frames.rb
142
+ - lib/krakow/connection_features/ssl.rb
143
+ - lib/krakow/consumer.rb
144
+ - lib/krakow/consumer/queue.rb
145
+ - lib/krakow/discovery.rb
146
+ - lib/krakow/distribution.rb
147
+ - lib/krakow/distribution/default.rb
148
+ - lib/krakow/exceptions.rb
149
+ - lib/krakow/frame_type.rb
150
+ - lib/krakow/frame_type/error.rb
151
+ - lib/krakow/frame_type/message.rb
152
+ - lib/krakow/frame_type/response.rb
153
+ - lib/krakow/ksocket.rb
154
+ - lib/krakow/producer.rb
155
+ - lib/krakow/producer/http.rb
156
+ - lib/krakow/utils.rb
157
+ - lib/krakow/utils/lazy.rb
158
+ - lib/krakow/utils/logging.rb
159
+ - lib/krakow/version.rb
160
+ homepage: http://github.com/chrisroberts/krakow
161
+ licenses:
162
+ - Apache 2.0
163
+ metadata: {}
164
+ post_install_message:
165
+ rdoc_options: []
166
+ require_paths:
167
+ - lib
168
+ required_ruby_version: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ required_rubygems_version: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ version: '0'
178
+ requirements: []
179
+ rubyforge_project:
180
+ rubygems_version: 2.5.1
181
+ signing_key:
182
+ specification_version: 4
183
+ summary: NSQ library
184
+ test_files: []