brown 1.1.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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