brown 1.1.2 → 2.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.
@@ -1,57 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
-
3
- require 'tmpdir'
4
- require 'protobuf'
5
-
6
- require "brown/logger"
7
-
8
- class Brown::ACLLoader
9
- extend Brown::Logger
10
-
11
- def self.load_all(*dirs)
12
- dirs.flatten!
13
- pfiles = dirs.each_with_object([]) do |dir, list|
14
- list << Dir["#{dir}/*.proto"]
15
- end.flatten
16
-
17
- load_proto_files(pfiles, dirs)
18
- end
19
-
20
- def self.load_proto_files(pfiles, dirs)
21
- orig_load_path = $LOAD_PATH
22
-
23
- Dir.mktmpdir do |tmpdir|
24
- dirs = pfiles.map { |f| File.dirname(f) }.uniq + [tmpdir]
25
- dirs.each { |d| $LOAD_PATH.unshift(d) }
26
-
27
- compiles = []
28
-
29
- pfiles.each do |f|
30
- pbrbfile = f.gsub(/\.proto$/, ".pb.rb")
31
- unless File.exists?(pbrbfile) and File.stat(pfile).mtime <= File.stat(pbrbfile).mtime
32
- compiles << f
33
- end
34
- end
35
-
36
- includes = dirs.map { |d| "-I '#{d}'" }.join(" ")
37
-
38
- unless compiles.empty?
39
- cmd = "protoc --ruby_out='#{tmpdir}' #{includes} #{compiles.map { |f| "'#{f}'" }.join(' ')} 2>&1"
40
- output = nil
41
-
42
- IO.popen(cmd) { |fd| output = fd.read }
43
-
44
- if $?.exitstatus != 0
45
- logger.fatal { "protoc failed: #{output}" }
46
- raise RuntimeError, output
47
- end
48
- end
49
-
50
- pfiles.each do |f|
51
- require "#{File.basename(f, '.proto')}.pb"
52
- end
53
- end
54
- ensure
55
- $LOAD_PATH.replace(orig_load_path)
56
- end
57
- end
@@ -1,52 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
-
3
- require 'extlib'
4
- require 'murmurhash3'
5
-
6
- module Brown::ACLLookup
7
- def get_by_hash(type)
8
- hashes[type]
9
- end
10
- module_function :get_by_hash
11
-
12
- def get_by_type(type)
13
- to_murmur32(type)
14
- end
15
- module_function :get_by_type
16
-
17
- # Look the key up in the cache. This defaults to the key being the hash.
18
- # If :by_type => true is passed in as the second argument then it will
19
- # perform the lookup in the type hash.
20
- #
21
- def include?(key, opts={})
22
- if opts[:by_type]
23
- !get_by_type(key).nil?
24
- else
25
- !get_by_hash(key).nil?
26
- end
27
- end
28
- module_function :include?
29
-
30
- def clear!
31
- @hashes = nil
32
- end
33
- module_function :clear!
34
-
35
- def hashes
36
- @hashes ||= begin
37
- map = ObjectSpace.each_object(Class).map do |k|
38
- [[to_murmur32(k), k], [k.to_s.split(/::/).last.snake_case, k]]
39
- end.flatten(1)
40
- Hash[map]
41
- end
42
- end
43
- module_function :hashes
44
-
45
- private
46
-
47
- # Convert the name to a base 36 murmur hash
48
- def to_murmur32(type)
49
- MurmurHash3::V32.murmur3_32_str_hash(type.to_s).to_s(36)
50
- end
51
- module_function :to_murmur32
52
- end
@@ -1,148 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
-
3
- module Brown::AmqpErrors
4
- def error_message(code, text, &blk)
5
- details = error_lookup(code)
6
- message = "#{details[:error_class]} exception: #{code} " +
7
- "(#{details[:name]}). #{details[:description]}"
8
-
9
- case code
10
- when 404
11
- diagnosis = "looks like the queue has been deleted."
12
- when 406
13
- case text
14
- when /.*(unknown delivery tag [0-9]+).*/
15
- diagnosis = "#{$1} - you've probably already acknowledged the message."
16
- end
17
- else
18
- end
19
- blk.call(message, diagnosis)
20
- end
21
-
22
- def error_lookup(code)
23
- errors[code]
24
- end
25
-
26
- def errors
27
- @errors ||= {
28
- 311 => {
29
- :name => "content-too-large",
30
- :error_class => "Channel",
31
- :description => "The client attempted to transfer content larger " +
32
- "than the server could accept at the present time. " +
33
- "The client may retry at a later time."
34
- },
35
- 313 => {
36
- :name => "no-consumers",
37
- :error_class => "Channel",
38
- :description => "When the exchange cannot deliver to a consumer " +
39
- "when the immediate flag is set. As a result of " +
40
- "pending data on the queue or the absence of any " +
41
- "consumers of the queue."
42
- },
43
- 320 => {
44
- :name => "connection-forced",
45
- :error_class => "Connection",
46
- :description => "An operator intervened to close the Connection " +
47
- "for some reason. The client may retry at some " +
48
- "later date."
49
- },
50
- 402 => {
51
- :name => "invalid-path",
52
- :error_class => "Connection",
53
- :description => "The client tried to work with an unknown virtual host."
54
- },
55
- 403 => {
56
- :name => "access-refused",
57
- :error_class => "Channel",
58
- :description => "The client attempted to work with a server " +
59
- "entity to which it has no access due to security " +
60
- "settings."
61
- },
62
- 404 => {
63
- :name => "not-found",
64
- :error_class => "Channel",
65
- :description => "The client attempted to work with a server " +
66
- "entity that does not exist."
67
- },
68
- 405 => {
69
- :name => "resource-locked",
70
- :error_class => "Channel",
71
- :description => "The client attempted to work with a server " +
72
- "entity to which it has no access because " +
73
- "another client is working with it."
74
- },
75
- 406 => {
76
- :name => "precondition-failed",
77
- :error_class => "Channel",
78
- :description => "The client requested a method that was not " +
79
- "allowed because some precondition failed."
80
- },
81
- 501 => {
82
- :name => "frame-error",
83
- :error_class => "Connection",
84
- :description => "The sender sent a malformed frame that the " +
85
- "recipient could not decode. This strongly " +
86
- "implies a programming error in the sending peer."
87
- },
88
- 502 => {
89
- :name => "syntax-error",
90
- :error_class => "Connection",
91
- :description => "The sender sent a frame that contained illegal " +
92
- "values for one or more fields. This strongly " +
93
- "implies a programming error in the sending peer."
94
- },
95
- 503 => {
96
- :name => "command-invalid",
97
- :error_class => "Connection",
98
- :description => "The client sent an invalid sequence of frames, " +
99
- "attempting to perform an operation that was " +
100
- "considered invalid by the server. This usually " +
101
- "implies a programming error in the client."
102
- },
103
- 504 => {
104
- :name => "channel-error",
105
- :error_class => "Connection",
106
- :description => "The client attempted to work with a Channel that " +
107
- "had not been correctly opened. This most likely " +
108
- "indicates a fault in the client layer."
109
- },
110
- 505 => {
111
- :name => "unexpected-frame",
112
- :error_class => "Connection",
113
- :description => "The peer sent a frame that was not expected, " +
114
- "usually in the context of a content header and " +
115
- "body. This strongly indicates a fault in the " +
116
- "peer's content processing."
117
- },
118
- 506 => {
119
- :name => "resource-error",
120
- :error_class => "Connection",
121
- :description => "The server could not complete the method because " +
122
- "it lacked sufficient resources. This may be due " +
123
- "to the client creating too many of some type of entity."
124
- },
125
- 530 => {
126
- :name => "not-allowed",
127
- :error_class => "Connection",
128
- :description => "The client tried to work with some entity in a " +
129
- "manner that is prohibited by the server, due to " +
130
- "security settings or by some other criteria."
131
- },
132
- 540 => {
133
- :name => "not-implemented",
134
- :error_class => "Connection",
135
- :description => "The client tried to use functionality that is " +
136
- "not implemented in the server."
137
- },
138
- 541 => {
139
- :name => "internal-error",
140
- :error_class => "Connection",
141
- :description => "The server could not complete the method " +
142
- "because of an internal error. The server may " +
143
- "require intervention by an operator in order " +
144
- "to resume normal operations."
145
- }
146
- }
147
- end
148
- end
@@ -1,51 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
-
3
- require 'logger'
4
-
5
- class Logger
6
- VERBOSE = 0.5
7
- TRACE = -1
8
-
9
- # Lack of prior planning, peeps!
10
- remove_const(:SEV_LABEL)
11
- SEV_LABEL = {
12
- TRACE => "TRACE",
13
- DEBUG => "DEBUG",
14
- VERBOSE => "VERB",
15
- INFO => "INFO",
16
- WARN => "WARN",
17
- ERROR => "ERROR",
18
- FATAL => "FATAL"
19
- }
20
-
21
- def verbose(progname = nil, &block)
22
- add(VERBOSE, nil, progname, &block)
23
- end
24
-
25
- def trace(progname = nil, &block)
26
- add(TRACE, nil, progname, &block)
27
- end
28
- end
29
-
30
- module Brown::Logger
31
- def logger
32
- @logger ||= begin
33
- Logger.new($stderr).tap do |l|
34
- l.formatter = proc { |s,dt,n,msg| "#{$$} [#{s[0]}] #{msg}\n" }
35
- l.level = Logger.const_get(Brown.log_level.upcase.to_sym)
36
- end
37
- end
38
- end
39
-
40
- def log_level(level=nil)
41
- if level
42
- logger.level = Logger.const_get(level.upcase.to_sym)
43
- end
44
- end
45
-
46
- def backtrace(ex)
47
- if ex.respond_to?(:backtrace) and ex.backtrace
48
- self.debug { ex.backtrace.map { |l| " #{l}" }.join("\n") }
49
- end
50
- end
51
- end
@@ -1,73 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
-
3
- require 'brown/logger'
4
-
5
- class Brown::Message
6
- include Brown::Logger
7
-
8
- attr_reader :payload, :metadata
9
-
10
- def initialize(payload, metadata, requeue_queue, requeue_options, opts = {}, &blk)
11
- @metadata = metadata
12
-
13
- @requeue_queue = requeue_queue
14
- @requeue_options = requeue_options
15
-
16
- @requeue_options[:strategy] ||= :linear
17
-
18
- @requeue_options[:on_requeue] ||= ->(count, total_count, cumulative_delay) {
19
- logger.info { "Requeuing (#{@requeue_options[:strategy]}) message on queue: #{@requeue_queue.name}, count: #{count} of #{total_count}." }
20
- }
21
-
22
- @requeue_options[:on_requeue_limit] ||= ->(message, count, total_count, cumulative_delay) {
23
- logger.info { "Not attempting any more requeues, requeue limit reached: #{total_count} for queue: #{@requeue_queue.name}, cummulative delay: #{cumulative_delay}s." }
24
- }
25
-
26
- klass = Brown::ACLLookup.get_by_hash(metadata.type)
27
- raise RuntimeError, "Unknown ACL: #{metadata.type}" if klass.nil?
28
-
29
- @payload = klass.new.parse_from_string(payload)
30
-
31
- blk.call(@payload, self)
32
- ack if opts[:auto_ack]
33
- end
34
-
35
- def ack(multiple = false)
36
- @metadata.ack(multiple)
37
- end
38
-
39
- def nak(opts = {})
40
- @metadata.reject(opts)
41
- end
42
-
43
- alias_method :reject, :nak
44
-
45
- def requeue
46
- if current_requeue_number < @requeue_options[:count]
47
- cumulative_delay = case @requeue_options[:strategy].to_sym
48
- when :linear
49
- @requeue_options[:delay] * (current_requeue_number + 1)
50
- when :exponential
51
- @requeue_options[:delay] * (2 ** current_requeue_number)
52
- when :exponential_no_initial_delay
53
- @requeue_options[:delay] * (2 ** current_requeue_number - 1)
54
- else
55
- raise RuntimeError, "Unknown requeue strategy #{@requeue_options[:strategy].to_sym.inspect}"
56
- end
57
-
58
- EM.add_timer(cumulative_delay) do
59
- new_headers = (@metadata.headers || {}).merge('requeue' => current_requeue_number + 1)
60
- @requeue_queue.publish(@payload, @metadata.to_hash.merge(:headers => new_headers))
61
- end
62
-
63
- @requeue_options[:on_requeue].call(current_requeue_number + 1, @requeue_options[:count], cumulative_delay)
64
- else
65
- @requeue_options[:on_requeue_limit].call(@payload, current_requeue_number + 1, @requeue_options[:count], @requeue_options[:delay] * current_requeue_number)
66
- end
67
- end
68
-
69
- private
70
- def current_requeue_number
71
- (@metadata.headers['requeue'] rescue nil) || 0
72
- end
73
- end
@@ -1,134 +0,0 @@
1
- # Remove any pre-existing activation of eventmachine, so that `eventmachine-le`
2
- # takes priority
3
- $:.delete_if { |d| d =~ /\/eventmachine-\d/ }
4
-
5
- require 'eventmachine-le'
6
- require 'amqp'
7
- require 'uri'
8
-
9
- require 'brown/logger'
10
-
11
- module Brown::ModuleMethods
12
- include Brown::Logger
13
-
14
- attr_reader :connection, :log_level
15
-
16
- def compile_acls
17
- end
18
-
19
- def config
20
- Class.new.tap do |cfg|
21
- cfg.send(:define_method, :method_missing) do |*_args|
22
- Class.new.tap do |group|
23
- group.send(:define_method, :method_missing) do |*_args|
24
- ""
25
- end
26
- end.new
27
- end
28
- end.new
29
- end
30
-
31
- def running?
32
- EM.reactor_running?
33
- end
34
-
35
- def start(opts={})
36
- @log_level = opts[:log_level] || "info"
37
-
38
- # Why these are not the defaults, I will never know
39
- EM.epoll if EM.epoll?
40
- EM.kqueue if EM.kqueue?
41
-
42
- connection_settings = {
43
- :on_tcp_connection_failure => method(:tcp_connection_failure_handler),
44
- :on_possible_authentication_failure => method(:authentication_failure_handler)
45
- }
46
-
47
- AMQP.start(opts[:server_url], connection_settings) do |connection|
48
- EM.threadpool_size = 1
49
- @connection = connection
50
-
51
- connection.on_connection do
52
- logger.info { "Connected to: AMQP Broker: #{broker_identifier(connection)}" }
53
- end
54
-
55
- connection.on_tcp_connection_loss do |connection, settings|
56
- logger.info { "Reconnecting to AMQP Broker: #{broker_identifier(connection)} in 5s" }
57
- connection.reconnect(false, 5)
58
- end
59
-
60
- connection.after_recovery do |connection|
61
- logger.info { "Connection with AMQP Broker restored: #{broker_identifier(connection)}" }
62
- end
63
-
64
- connection.on_error do |connection, connection_close|
65
- # If the broker is gracefully shutdown we get a 320. Log a nice message.
66
- if connection_close.reply_code == 320
67
- logger.info { "AMQP Broker shutdown: #{broker_identifier(connection)}" }
68
- else
69
- logger.warn { connection_close.reply_text }
70
- end
71
- end
72
-
73
- # This will be the last thing run by the reactor.
74
- shutdown_hook { logger.debug { "Reactor Stopped" } }
75
-
76
- yield if block_given?
77
- end
78
- end
79
-
80
- def shutdown_hook(&block)
81
- EM.add_shutdown_hook(&block)
82
- end
83
-
84
- def stop(immediately=false, &blk)
85
- shutdown_hook(&blk) if blk
86
-
87
- if running?
88
- if immediately
89
- EM.next_tick do
90
- @connection.close { EM.stop_event_loop }
91
- end
92
- else
93
- EM.add_timer(1) do
94
- @connection.close { EM.stop_event_loop }
95
- end
96
- end
97
- else
98
- logger.fatal { "Eventmachine is not running, exiting with prejudice" }
99
- exit!
100
- end
101
- end
102
-
103
- private
104
-
105
- def tcp_connection_failure_handler(settings)
106
- # Only display the following settings.
107
- s = settings.select { |k,v| ([:user, :pass, :vhost, :host, :port, :ssl].include?(k)) }
108
-
109
- logger.fatal { "Cannot connect to the AMQP server." }
110
- logger.fatal { "Is the server running and are the connection details correct?" }
111
- logger.info { "Details:" }
112
- s.each do |k,v|
113
- logger.info { " Setting: %-7s%s" % [k, v] }
114
- end
115
- EM.stop
116
- end
117
-
118
- def authentication_failure_handler(settings)
119
- # Only display the following settings.
120
- s = settings.select { |k,v| [:user, :pass, :vhost, :host].include?(k) }
121
-
122
- logger.fatal { "Authentication failure." }
123
- logger.info { "Details:" }
124
- s.each do |k,v|
125
- logger.info { " Setting: %-7s%s" % [k, v] }
126
- end
127
- EM.stop
128
- end
129
-
130
- def broker_identifier(connection)
131
- broker = connection.broker.properties
132
- "#{connection.broker_endpoint}, (#{broker['product']}/v#{broker['version']})"
133
- end
134
- end