pushyd 0.9.4 → 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +22 -17
- data/bin/pushyd +12 -6
- data/defaults.yml +8 -4
- data/lib/pushyd/constants.rb +9 -13
- data/lib/pushyd/consumer.rb +144 -0
- data/lib/pushyd/daemon.rb +3 -11
- data/lib/pushyd/initialize.rb +3 -0
- data/lib/pushyd/proxy.rb +67 -135
- data/lib/pushyd/shouter.rb +43 -43
- data/lib/pushyd.rb +6 -1
- data/lib/shared/hmac_signature.rb +25 -14
- data/pushyd.gemspec +3 -2
- metadata +20 -5
- data/lib/pushyd/endpoint.rb +0 -137
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f28f30eb8e374a96c94d9db2e3211cb96e130805
|
4
|
+
data.tar.gz: 2b3f74b4cf520b66847c1626c44e3257e6310a49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 20bb1cc397e0d112988e0f8988645a553eefb19c288c81a49d531e4fc644607a45a160c3db0ff77c76a2e2e13666d877a44072e585baaf4553120ab6b56def2d
|
7
|
+
data.tar.gz: 167aa4659b654a46195671d00d46d6a205b19fb528aac492d6c0b8cc12ad4b8580b02975b9365eee082780785e574e8601dd26a01f8c386629a42a3f69ad9b92
|
data/Gemfile.lock
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pushyd (0.
|
4
|
+
pushyd (0.20.0)
|
5
5
|
api-auth
|
6
|
-
bmc-daemon-lib (~> 0.
|
6
|
+
bmc-daemon-lib (~> 0.3.14)
|
7
7
|
bunny (~> 2.3)
|
8
8
|
daemons
|
9
9
|
json
|
10
10
|
newrelic_rpm
|
11
11
|
rest-client (~> 1.8)
|
12
|
+
rollbar
|
12
13
|
terminal-table
|
13
14
|
|
14
15
|
GEM
|
@@ -16,21 +17,21 @@ GEM
|
|
16
17
|
specs:
|
17
18
|
addressable (2.4.0)
|
18
19
|
amq-protocol (2.0.1)
|
19
|
-
api-auth (2.0.
|
20
|
+
api-auth (2.0.1)
|
20
21
|
ast (2.3.0)
|
21
|
-
bmc-daemon-lib (0.
|
22
|
+
bmc-daemon-lib (0.3.14)
|
22
23
|
chamber (~> 2.9)
|
23
|
-
bunny (2.5.
|
24
|
+
bunny (2.5.1)
|
24
25
|
amq-protocol (>= 2.0.1)
|
25
|
-
chamber (2.9.
|
26
|
+
chamber (2.9.1)
|
26
27
|
hashie (~> 3.3)
|
27
28
|
thor (~> 0.19.1)
|
28
|
-
daemons (1.2.
|
29
|
+
daemons (1.2.4)
|
29
30
|
diff-lcs (1.2.5)
|
30
|
-
domain_name (0.5.
|
31
|
+
domain_name (0.5.20160826)
|
31
32
|
unf (>= 0.0.5, < 1.0.0)
|
32
33
|
hashie (3.4.4)
|
33
|
-
http (2.0.
|
34
|
+
http (2.0.3)
|
34
35
|
addressable (~> 2.3)
|
35
36
|
http-cookie (~> 1.0)
|
36
37
|
http-form_data (~> 1.0.1)
|
@@ -39,10 +40,11 @@ GEM
|
|
39
40
|
domain_name (~> 0.5)
|
40
41
|
http-form_data (1.0.1)
|
41
42
|
http_parser.rb (0.6.0)
|
42
|
-
json (2.0.
|
43
|
-
mime-types (2.99.
|
43
|
+
json (2.0.2)
|
44
|
+
mime-types (2.99.3)
|
45
|
+
multi_json (1.12.1)
|
44
46
|
netrc (0.11.0)
|
45
|
-
newrelic_rpm (3.16.
|
47
|
+
newrelic_rpm (3.16.2.321)
|
46
48
|
parser (2.3.1.2)
|
47
49
|
ast (~> 2.2)
|
48
50
|
powerpack (0.1.1)
|
@@ -52,11 +54,13 @@ GEM
|
|
52
54
|
http-cookie (>= 1.0.2, < 2.0)
|
53
55
|
mime-types (>= 1.16, < 3.0)
|
54
56
|
netrc (~> 0.7)
|
57
|
+
rollbar (2.12.0)
|
58
|
+
multi_json
|
55
59
|
rspec (3.5.0)
|
56
60
|
rspec-core (~> 3.5.0)
|
57
61
|
rspec-expectations (~> 3.5.0)
|
58
62
|
rspec-mocks (~> 3.5.0)
|
59
|
-
rspec-core (3.5.
|
63
|
+
rspec-core (3.5.3)
|
60
64
|
rspec-support (~> 3.5.0)
|
61
65
|
rspec-expectations (3.5.0)
|
62
66
|
diff-lcs (>= 1.2.0, < 2.0)
|
@@ -65,19 +69,20 @@ GEM
|
|
65
69
|
diff-lcs (>= 1.2.0, < 2.0)
|
66
70
|
rspec-support (~> 3.5.0)
|
67
71
|
rspec-support (3.5.0)
|
68
|
-
rubocop (0.
|
72
|
+
rubocop (0.42.0)
|
69
73
|
parser (>= 2.3.1.1, < 3.0)
|
70
74
|
powerpack (~> 0.1)
|
71
75
|
rainbow (>= 1.99.1, < 3.0)
|
72
76
|
ruby-progressbar (~> 1.7)
|
73
77
|
unicode-display_width (~> 1.0, >= 1.0.1)
|
74
78
|
ruby-progressbar (1.8.1)
|
75
|
-
terminal-table (1.
|
79
|
+
terminal-table (1.7.2)
|
80
|
+
unicode-display_width (~> 1.1.1)
|
76
81
|
thor (0.19.1)
|
77
82
|
unf (0.1.4)
|
78
83
|
unf_ext
|
79
84
|
unf_ext (0.0.7.2)
|
80
|
-
unicode-display_width (1.1.
|
85
|
+
unicode-display_width (1.1.1)
|
81
86
|
|
82
87
|
PLATFORMS
|
83
88
|
ruby
|
@@ -91,4 +96,4 @@ DEPENDENCIES
|
|
91
96
|
rubocop
|
92
97
|
|
93
98
|
BUNDLED WITH
|
94
|
-
1.
|
99
|
+
1.12.5
|
data/bin/pushyd
CHANGED
@@ -17,6 +17,7 @@ begin
|
|
17
17
|
# Defaults
|
18
18
|
cmd_config = nil
|
19
19
|
cmd_logfile = nil
|
20
|
+
cmd_dump = nil
|
20
21
|
|
21
22
|
# Init Chamber-based configuration from Gemspec
|
22
23
|
Conf.init File.dirname(__FILE__) + "/../"
|
@@ -25,10 +26,11 @@ begin
|
|
25
26
|
# Parse options and check compliance
|
26
27
|
parser = OptionParser.new do |opts|
|
27
28
|
opts.banner = "Usage: #{File.basename $PROGRAM_NAME} [options] start|stop"
|
28
|
-
opts.on("-l", "--log LOGFILE")
|
29
|
-
opts.on("-c", "--config CONFIGFILE")
|
30
|
-
opts.on("-e", "--environment ENV")
|
31
|
-
opts.on("", "--dev")
|
29
|
+
opts.on("-l", "--log LOGFILE") { |path| cmd_logfile = File.expand_path(path.to_s)}
|
30
|
+
opts.on("-c", "--config CONFIGFILE") { |path| cmd_config = File.expand_path(path.to_s)}
|
31
|
+
opts.on("-e", "--environment ENV") { |env| Conf.app_env = env }
|
32
|
+
opts.on("", "--dev") { Conf.app_env = "development" }
|
33
|
+
opts.on("", "--dump", "Dump config as seen by the process") { |value| cmd_dump = true }
|
32
34
|
end
|
33
35
|
parser.order!(ARGV)
|
34
36
|
|
@@ -55,8 +57,12 @@ puts "Config files \t #{Conf.files}"
|
|
55
57
|
puts "Started at \t #{Conf.app_started}"
|
56
58
|
puts "Loging to file \t #{Conf[:log][:file]}" if Conf[:log].is_a? Enumerable
|
57
59
|
puts "Process name \t #{Conf.generate(:process_name)}"
|
58
|
-
puts
|
59
|
-
puts Conf.
|
60
|
+
puts "Newrelic \t #{Conf.feature?(:newrelic) || '-'}"
|
61
|
+
puts "Rollbar \t #{Conf.feature?(:rollbar) || '-'}"
|
62
|
+
if cmd_dump
|
63
|
+
puts
|
64
|
+
puts Conf.dump
|
65
|
+
end
|
60
66
|
|
61
67
|
# Run daemon
|
62
68
|
run_options = {
|
data/defaults.yml
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
# common defaults
|
2
2
|
broker: amqp://guest:guest@localhost:5672/%2F
|
3
|
+
|
3
4
|
logs:
|
4
|
-
path:
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
path: "/tmp/"
|
6
|
+
level: debug
|
7
|
+
default: "pushyd-default.log"
|
8
|
+
shouter: "pushyd-shouter.log"
|
9
|
+
consumer: "pushyd-consumer.log"
|
10
|
+
# newrelic: "pushyd-newrelic.log"
|
11
|
+
# rollbar: "pushyd-rollbar.log"
|
8
12
|
|
9
13
|
shout:
|
10
14
|
topic: pushyd
|
data/lib/pushyd/constants.rb
CHANGED
@@ -1,29 +1,25 @@
|
|
1
1
|
# Constants: global
|
2
2
|
MSG_SEND = "SEND"
|
3
3
|
MSG_RECV = "RECV"
|
4
|
-
|
4
|
+
MSG_RLAY = "RLAY"
|
5
5
|
|
6
|
-
# Constants:
|
7
|
-
|
8
|
-
|
6
|
+
# Constants: AMQP protocol
|
7
|
+
AMQP_HEARTBEAT_INTERVAL = 30
|
8
|
+
AMQP_RECOVERY_INTERVAL = 5
|
9
|
+
AMQP_PREFETCH = 3
|
10
|
+
AMQP_MANUAL_ACK = false
|
9
11
|
|
10
12
|
# Constants: shouter
|
11
13
|
SHOUTER_SENTAT_DECIMALS = 6
|
12
14
|
|
13
15
|
# Constants: logger
|
14
|
-
LOG_ROTATION = "daily"
|
15
|
-
|
16
16
|
LOG_HEADER_TIME = "%Y-%m-%d %H:%M:%S"
|
17
17
|
LOG_HEADER_FORMAT = "%s \t%d\t%-8s %-15s "
|
18
|
-
LOG_MESSAGE_TRIM =
|
18
|
+
LOG_MESSAGE_TRIM = 250
|
19
19
|
LOG_MESSAGE_TEXT = "%s%s"
|
20
20
|
LOG_MESSAGE_ARRAY = "%s %s"
|
21
21
|
LOG_MESSAGE_HASH = "%s %-20s %s\n"
|
22
22
|
|
23
23
|
# Constants: logger app-specific prefix
|
24
|
-
LOG_PREFIX_FORMAT =
|
25
|
-
|
26
|
-
# Constants: AMQP protocol
|
27
|
-
AMQP_HEARTBEAT_INTERVAL = 30
|
28
|
-
AMQP_RECOVERY_INTERVAL = 5
|
29
|
-
AMQP_PREFETCH = 2
|
24
|
+
#LOG_PREFIX_FORMAT = "(%-12s) (%-12s)"
|
25
|
+
LOG_PREFIX_FORMAT = "%-20s "
|
@@ -0,0 +1,144 @@
|
|
1
|
+
module PushyDaemon
|
2
|
+
# class ShouterResponseError < StandardError; end
|
3
|
+
# class ShouterChannelClosed < StandardError; end
|
4
|
+
# class ShouterPreconditionFailed < StandardError; end
|
5
|
+
# class ShouterInterrupted < StandardError; end
|
6
|
+
class ConsumerError < StandardError; end
|
7
|
+
class ConsumerRuleMissing < StandardError; end
|
8
|
+
|
9
|
+
class Consumer < BmcDaemonLib::MqConsumer
|
10
|
+
#include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
11
|
+
include Shared::HmacSignature
|
12
|
+
attr_accessor :logger
|
13
|
+
|
14
|
+
def initialize(conn, rule_name, rule)
|
15
|
+
# Init
|
16
|
+
@queue = nil
|
17
|
+
@conn = conn
|
18
|
+
@rule = rule
|
19
|
+
@rule_name = rule_name
|
20
|
+
|
21
|
+
# Prepare logger
|
22
|
+
@logger = BmcDaemonLib::LoggerPool.instance.get :consumer
|
23
|
+
|
24
|
+
# Create channel, prefetch only one message at a time
|
25
|
+
@channel = @conn.create_channel
|
26
|
+
@channel.prefetch(AMQP_PREFETCH)
|
27
|
+
|
28
|
+
# OK
|
29
|
+
log_info "Consumer initialized"
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def log_prefix
|
35
|
+
[@rule_name]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Handle the reception of a message on a queue
|
39
|
+
def handle_message context, metadata, delivery_info, message = {}
|
40
|
+
# Prepare data
|
41
|
+
headers = metadata.headers || {}
|
42
|
+
|
43
|
+
# Relay data if needed
|
44
|
+
handle_relay context, message, headers
|
45
|
+
|
46
|
+
# Handle errors and acknowledgments
|
47
|
+
# log_debug "handle_message : channel[#{@channel.inspect}]"
|
48
|
+
rescue StandardError => e
|
49
|
+
log_error "handle_message: unknown: #{e.message}, #{e.inspect}", e.backtrace
|
50
|
+
channel_ackit(message[:tag], false)
|
51
|
+
else
|
52
|
+
channel_ackit(message[:tag], true)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def handle_relay context, message, headers
|
58
|
+
# Check we have a valid @rule
|
59
|
+
raise ConsumerRuleMissing unless @rule.is_a? Hash
|
60
|
+
|
61
|
+
# Check if we need to relay anything
|
62
|
+
unless @rule[:relay]
|
63
|
+
log_debug "handle_relay: no [relay] URL"
|
64
|
+
return
|
65
|
+
end
|
66
|
+
|
67
|
+
# Prepare stuff
|
68
|
+
relay_auth = @rule[:auth].to_s
|
69
|
+
relay_url = URI(@rule[:relay]).to_s
|
70
|
+
request_id = identifier(6)
|
71
|
+
request_prefix = "handle_relay [#{request_id}] "
|
72
|
+
|
73
|
+
# Build payload
|
74
|
+
request_infos = {
|
75
|
+
topic: message[:topic],
|
76
|
+
route: message[:rkey],
|
77
|
+
sent_at: headers['sent_at'],
|
78
|
+
sent_by: headers['sent_by'],
|
79
|
+
context: context,
|
80
|
+
data: message[:data],
|
81
|
+
}
|
82
|
+
request_body = JSON.pretty_generate(request_infos)
|
83
|
+
|
84
|
+
# Build request headers
|
85
|
+
headers = {
|
86
|
+
content_type: :json,
|
87
|
+
accept: :json,
|
88
|
+
user_agent: BmcDaemonLib::Conf.generate(:user_agent),
|
89
|
+
}
|
90
|
+
|
91
|
+
# Compute: payload MD5, HMAC signature
|
92
|
+
headers_md5 headers, request_body
|
93
|
+
headers_sign headers, @rule[:sign], [:date]
|
94
|
+
|
95
|
+
# Build final request
|
96
|
+
request = RestClient::Request.new url: relay_url,
|
97
|
+
method: :post,
|
98
|
+
payload: request_body,
|
99
|
+
headers: headers
|
100
|
+
|
101
|
+
# Execute request
|
102
|
+
log_message MSG_RLAY, request_id, relay_url, request_infos, request.processed_headers
|
103
|
+
response = request.execute
|
104
|
+
|
105
|
+
# Handle exceptions
|
106
|
+
rescue RestClient::ExceptionWithResponse, URI::InvalidURIError, RestClient::InternalServerError => e
|
107
|
+
log_error "#{request_prefix} rest-client exception: #{e.message}"
|
108
|
+
rescue ApiAuth::ApiAuthError, ApiAuth::UnknownHTTPRequest => e
|
109
|
+
log_error "#{request_prefix} api-auth: #{e.message}"
|
110
|
+
rescue Errno::ECONNREFUSED => e
|
111
|
+
log_error "#{request_prefix} connection refused: #{e.message}"
|
112
|
+
rescue StandardError => e
|
113
|
+
log_error "#{request_prefix} unknown: #{e.message}, #{e.inspect}", e.backtrace
|
114
|
+
else
|
115
|
+
log_info "#{request_prefix} received [#{response.body}]"
|
116
|
+
end
|
117
|
+
|
118
|
+
def channel_ackit tag, success=true
|
119
|
+
# log_debug "channel_ackit[#{channel}.#{tag}] #{@channel.inspect}"
|
120
|
+
# if success
|
121
|
+
# log_debug "channel_ackit[#{@channel.id}.#{tag}]: ACK"
|
122
|
+
# @channel.ack(tag)
|
123
|
+
# else
|
124
|
+
# log_debug "channel_ackit[#{@channel.id}.#{tag}]: NACK"
|
125
|
+
# @channel.nack(tag)
|
126
|
+
# end
|
127
|
+
|
128
|
+
# rescue Bunny::ChannelAlreadyClosed => ex
|
129
|
+
# error "channel_ackit[#{@channel.id}.#{tag}]: exception: ChannelAlreadyClosed"
|
130
|
+
|
131
|
+
# rescue StandardError => ex
|
132
|
+
# log_debug "channel_ackit[#{@channel.id}.#{tag}]: exception: #{ex.inspect}"
|
133
|
+
# # fail PushyDaemon::EndpointSubscribeError, "unhandled (#{e.inspect})"
|
134
|
+
|
135
|
+
# else
|
136
|
+
# log_debug "channel_ackit[#{@channel.id}.#{tag}]: done"
|
137
|
+
end
|
138
|
+
|
139
|
+
# NewRelic instrumentation
|
140
|
+
#add_transaction_tracer :receive, category: :task
|
141
|
+
#add_transaction_tracer :propagate, category: :task
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
data/lib/pushyd/daemon.rb
CHANGED
@@ -2,20 +2,12 @@ module PushyDaemon
|
|
2
2
|
class Daemon
|
3
3
|
|
4
4
|
def self.run
|
5
|
-
# Create a new proxy
|
6
|
-
|
7
|
-
|
8
|
-
# Dump config table
|
9
|
-
puts p.table.to_s
|
10
|
-
|
11
|
-
# Create a new shouter
|
12
|
-
s = Shouter.new
|
13
|
-
|
14
|
-
# Start shout loop
|
15
|
-
s.shout
|
5
|
+
# Create a new proxy, and dump its configuration
|
6
|
+
Proxy.new
|
16
7
|
|
17
8
|
# Backup infinite loop in case shout does nothing
|
18
9
|
loop do
|
10
|
+
sleep 1
|
19
11
|
end
|
20
12
|
|
21
13
|
rescue EndpointConnectionError, ShouterInterrupted => e
|
data/lib/pushyd/proxy.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
+
require "bunny"
|
1
2
|
require 'api_auth'
|
2
3
|
require 'rest_client'
|
3
4
|
require 'terminal-table'
|
4
5
|
|
5
6
|
module PushyDaemon
|
6
|
-
class Proxy <
|
7
|
-
include
|
8
|
-
include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
7
|
+
class Proxy < BmcDaemonLib::MqEndpoint
|
8
|
+
#include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
9
9
|
|
10
10
|
# Class options
|
11
11
|
attr_accessor :table
|
12
12
|
|
13
13
|
def initialize
|
14
14
|
# Init
|
15
|
-
|
16
|
-
@
|
15
|
+
@shouters = []
|
16
|
+
@consumers = []
|
17
17
|
|
18
18
|
# Init ASCII table
|
19
19
|
@table = Terminal::Table.new
|
@@ -21,155 +21,87 @@ module PushyDaemon
|
|
21
21
|
@table.headings = ["rule", "topic", "route", "relay", "created queue", "description"]
|
22
22
|
@table.align_column(5, :right)
|
23
23
|
|
24
|
-
#
|
25
|
-
@
|
26
|
-
log_info "channel connected"
|
24
|
+
# Prepare logger
|
25
|
+
@logger = BmcDaemonLib::LoggerPool.instance.get
|
27
26
|
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
rule[:name] = name
|
38
|
-
channel_subscribe rule
|
39
|
-
end
|
40
|
-
end
|
27
|
+
# Start connexion to RabbitMQ
|
28
|
+
@conn = connect_to BmcDaemonLib::Conf[:broker]
|
29
|
+
log_info "Proxy connected"
|
30
|
+
|
31
|
+
# Check config and subscribe rules
|
32
|
+
create_consumers
|
33
|
+
|
34
|
+
# Create a new shouter, and start its loop
|
35
|
+
create_shouter
|
41
36
|
|
42
37
|
# Send config table to logs
|
43
|
-
log_info "
|
38
|
+
log_info "Proxy initialized", @table.to_s.lines
|
44
39
|
end
|
45
40
|
|
46
41
|
protected
|
47
42
|
|
48
|
-
|
43
|
+
def log_prefix
|
44
|
+
[nil]
|
45
|
+
# [self.class.name.split('::').last, :proxy]
|
46
|
+
end
|
49
47
|
|
50
|
-
def
|
51
|
-
|
48
|
+
def create_shouter
|
49
|
+
# Get config
|
50
|
+
config_shouter = BmcDaemonLib::Conf[:shout]
|
52
51
|
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
-
# log_info "timenow : #{Time.now.to_f}"
|
52
|
+
# Create the shouter
|
53
|
+
shouter = Shouter.new(@conn, config_shouter)
|
54
|
+
@shouters << shouter
|
57
55
|
|
58
|
-
#
|
59
|
-
|
56
|
+
# Now make it loop
|
57
|
+
shouter.start_loop
|
60
58
|
end
|
61
59
|
|
60
|
+
def create_consumers
|
61
|
+
# Get config
|
62
|
+
config_rules = BmcDaemonLib::Conf[:rules]
|
63
|
+
log_info "create_consumers: #{config_rules.keys.join(', ')}"
|
62
64
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
msg_exchange = delivery_info.exchange
|
68
|
-
msg_rkey = delivery_info.routing_key.force_encoding('UTF-8')
|
69
|
-
msg_headers = metadata.headers || {}
|
70
|
-
|
71
|
-
# Compute delay and size
|
72
|
-
delay = extract_delay(msg_headers)
|
73
|
-
size = format_bytes(payload.bytesize, "B")
|
74
|
-
|
75
|
-
# Extract payload
|
76
|
-
data = parse payload, metadata.content_type
|
77
|
-
|
78
|
-
# Announce match
|
79
|
-
log_message MSG_RECV, msg_exchange, msg_rkey, data, {
|
80
|
-
'matched rule' => rule_name,
|
81
|
-
'app-id' => metadata.app_id,
|
82
|
-
'content-type' => metadata.content_type,
|
83
|
-
'delay (ms)' => delay,
|
84
|
-
'body size' => size,
|
85
|
-
}
|
86
|
-
|
87
|
-
# Build notification payload
|
88
|
-
propagate_data = {
|
89
|
-
exchange: msg_exchange,
|
90
|
-
route: msg_rkey,
|
91
|
-
sent_at: msg_headers['sent_at'],
|
92
|
-
sent_by: msg_headers['sent_by'],
|
93
|
-
data: data,
|
94
|
-
}
|
95
|
-
|
96
|
-
# Propagate data if needed
|
97
|
-
propagate rule, propagate_data
|
98
|
-
end
|
65
|
+
if config_rules.nil? || !config_rules.is_a?(Hash)
|
66
|
+
log_error "prepare: no rules"
|
67
|
+
return
|
68
|
+
end
|
99
69
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
relay_auth = rule[:auth].to_s
|
106
|
-
relay_uri = URI(rule[:relay])
|
107
|
-
relay_url = relay_uri.to_s
|
108
|
-
id = identifier(6)
|
109
|
-
# log_info "propagate: user[#{relay_uri.user}] url[#{relay_url}]"
|
110
|
-
|
111
|
-
# Build POST body and log message
|
112
|
-
post_body = JSON.pretty_generate(data)
|
113
|
-
log_message WAY_PROP, id, relay_url, data
|
114
|
-
|
115
|
-
# Prepare request
|
116
|
-
request = RestClient::Request.new url: relay_url,
|
117
|
-
method: :post,
|
118
|
-
payload: post_body,
|
119
|
-
headers: {
|
120
|
-
content_type: :json,
|
121
|
-
accept: :json,
|
122
|
-
user_agent: Conf.generate(:user_agent),
|
123
|
-
}
|
124
|
-
|
125
|
-
# Compute payload MD5
|
126
|
-
headers_md5 request
|
127
|
-
|
128
|
-
# Compute HMAC signature
|
129
|
-
headers_sign request, rule['hmac-method'], rule['hmac-user'], rule['hmac-secret'], [:date]
|
130
|
-
|
131
|
-
# Send request
|
132
|
-
log_info "propagate: #{relay_url}", request.headers
|
133
|
-
response = request.execute
|
134
|
-
|
135
|
-
# Handle exceptions
|
136
|
-
rescue RestClient::ExceptionWithResponse, URI::InvalidURIError => e
|
137
|
-
log_error "propagate: rest-client: #{e.message}"
|
138
|
-
rescue RestClient::InternalServerError => e
|
139
|
-
log_error "propagate: rest-client: #{e.message}"
|
140
|
-
rescue ApiAuth::ApiAuthError, ApiAuth::UnknownHTTPRequest => e
|
141
|
-
log_error "propagate: api-auth: #{e.message}"
|
142
|
-
rescue Errno::ECONNREFUSED => e
|
143
|
-
log_error "propagate: connection refused: #{e.message}"
|
144
|
-
rescue StandardError => e
|
145
|
-
log_error "propagate: unknown: #{e.message}, #{e.inspect}", e.backtrace
|
146
|
-
else
|
147
|
-
log_info "propagate: #{response.body}"
|
70
|
+
# Subscribe for each and every rule/route
|
71
|
+
config_rules.each do |name, rule|
|
72
|
+
rule[:name] = name
|
73
|
+
create_consumer rule
|
74
|
+
end
|
148
75
|
end
|
149
76
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
77
|
+
# Subscribe to interesting topic/routes and bind a listenner
|
78
|
+
def create_consumer rule
|
79
|
+
# Check information
|
80
|
+
rule_name = rule[:name].to_s
|
81
|
+
rule_topic = rule[:topic].to_s
|
82
|
+
rule_routes = rule[:routes].to_s.split(' ')
|
83
|
+
rule_queue = sprintf('%s-%s', BmcDaemonLib::Conf.app_name, rule_name.gsub('_', '-'))
|
84
|
+
|
85
|
+
fail PushyDaemon::EndpointSubscribeContext, "rule [#{rule_name}] lacking topic" unless rule_topic
|
86
|
+
fail PushyDaemon::EndpointSubscribeContext, "rule [#{rule_name}] lacking routes" if rule_routes.empty?
|
87
|
+
|
88
|
+
# Build a new consumer
|
89
|
+
consumer = Consumer.new(@conn, rule_name, rule)
|
90
|
+
|
91
|
+
# Create its own queue
|
92
|
+
consumer.subscribe_to_queue rule_queue, "rule:#{rule_name}"
|
93
|
+
|
94
|
+
# Bind each route to exchange
|
95
|
+
rule_routes.each do |route|
|
96
|
+
consumer.listen_to rule_topic, route
|
97
|
+
|
98
|
+
# Add row to config table
|
99
|
+
@table.add_row [rule_name, rule_topic, route, rule[:relay].to_s, rule_queue, rule[:title].to_s ]
|
162
100
|
end
|
163
101
|
|
164
|
-
|
165
|
-
|
166
|
-
log_error "parse: JSON PARSE ERROR: #{e.inspect}"
|
167
|
-
return {}
|
102
|
+
# Return it
|
103
|
+
@consumers << consumer
|
168
104
|
end
|
169
105
|
|
170
|
-
# NewRelic instrumentation
|
171
|
-
add_transaction_tracer :handle_message, category: :task
|
172
|
-
add_transaction_tracer :propagate, category: :task
|
173
|
-
|
174
106
|
end
|
175
107
|
end
|
data/lib/pushyd/shouter.rb
CHANGED
@@ -5,63 +5,55 @@ module PushyDaemon
|
|
5
5
|
class ShouterInterrupted < StandardError; end
|
6
6
|
class EndpointTopicContext < StandardError; end
|
7
7
|
|
8
|
-
class Shouter <
|
8
|
+
class Shouter < BmcDaemonLib::MqEndpoint
|
9
9
|
include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
10
|
+
include BmcDaemonLib::LoggerHelper
|
10
11
|
|
11
12
|
# Class options
|
12
13
|
attr_accessor :table
|
14
|
+
attr_accessor :logger
|
13
15
|
|
14
|
-
def initialize
|
16
|
+
def initialize(conn, config_shout)
|
15
17
|
# Init
|
16
|
-
|
17
|
-
@
|
18
|
+
@shouter_keys = []
|
19
|
+
@channel = nil
|
20
|
+
@exchange = nil
|
21
|
+
|
22
|
+
# Prepare logger
|
23
|
+
@logger = BmcDaemonLib::LoggerPool.instance.get :shouter
|
18
24
|
|
19
25
|
# Check config
|
20
|
-
config_shout = Conf[:shout]
|
21
26
|
unless config_shout && config_shout.any? && config_shout.is_a?(Enumerable)
|
22
27
|
log_error "prepare: empty [shout] section"
|
23
28
|
return
|
24
29
|
end
|
25
30
|
|
26
31
|
# Extract information
|
27
|
-
@
|
28
|
-
@
|
29
|
-
@
|
32
|
+
@shouter_keys = config_shout[:keys] if config_shout[:keys].is_a? Array
|
33
|
+
@shouter_topic = config_shout[:topic]
|
34
|
+
@shouter_period = config_shout[:period].to_i
|
35
|
+
@shouter_period = 1 unless (@shouter_period > 0)
|
30
36
|
|
31
|
-
|
32
|
-
@channel = connect_channel Conf[:broker]
|
33
|
-
log_info "channel connected"
|
37
|
+
fail PushyDaemon::EndpointTopicContext unless @shouter_topic
|
34
38
|
|
35
|
-
# Create exchange
|
36
|
-
|
37
|
-
@exchange = @channel.topic(@
|
39
|
+
# Create channel and exchange
|
40
|
+
@channel = conn.create_channel
|
41
|
+
@exchange = @channel.topic(@shouter_topic, durable: true, persistent: true)
|
38
42
|
|
39
|
-
#
|
40
|
-
|
41
|
-
log_info "shouter initialized", shouter_info
|
43
|
+
# Start working, now
|
44
|
+
log_info "Shouter initialized, starting loop now", { topic: @shouter_topic, period: @shouter_period, keys: @shouter_keys }
|
42
45
|
end
|
43
46
|
|
44
|
-
def
|
45
|
-
return unless @exchange
|
46
|
-
|
47
|
+
def start_loop
|
47
48
|
# Prepare exchange
|
48
49
|
loop do
|
49
|
-
# Generate key and fake id
|
50
|
-
if @keys.is_a?(Array) && @keys.any?
|
51
|
-
random_key = @keys.sample
|
52
|
-
else
|
53
|
-
random_key = "random"
|
54
|
-
end
|
55
|
-
# random_key = @keys.class
|
56
|
-
random_string = SecureRandom.hex
|
57
|
-
|
58
50
|
# Generate payload
|
59
|
-
|
60
|
-
payload = nil
|
51
|
+
payload = {time: Time.now.to_f, host: BmcDaemonLib::Conf.host}
|
52
|
+
# payload = nil
|
61
53
|
|
62
54
|
# Shout it !
|
63
|
-
|
64
|
-
sleep @
|
55
|
+
exchange_shout @exchange, payload
|
56
|
+
sleep @shouter_period
|
65
57
|
end
|
66
58
|
rescue AMQ::Protocol::EmptyResponseError => e
|
67
59
|
fail PushyDaemon::ShouterResponseError, "#{e.class} (#{e.inspect})"
|
@@ -76,35 +68,43 @@ module PushyDaemon
|
|
76
68
|
|
77
69
|
protected
|
78
70
|
|
71
|
+
def log_prefix
|
72
|
+
[nil]
|
73
|
+
# [self.class.name.split('::').last, :shouter]
|
74
|
+
end
|
75
|
+
|
79
76
|
private
|
80
77
|
|
81
|
-
def
|
82
|
-
# Prepare
|
83
|
-
|
84
|
-
keys
|
78
|
+
def exchange_shout exchange, body = {}
|
79
|
+
# Prepare routing_key
|
80
|
+
keys = []
|
81
|
+
keys << @shouter_topic
|
82
|
+
keys << SecureRandom.hex
|
83
|
+
keys << @shouter_keys.sample if (@shouter_keys.is_a?(Array) && @shouter_keys.any?)
|
85
84
|
routing_key = keys.join('.')
|
86
85
|
|
87
86
|
# Announce shout
|
88
|
-
log_message MSG_SEND,
|
87
|
+
log_message MSG_SEND, @shouter_topic, routing_key, body
|
89
88
|
|
90
89
|
# Prepare headers
|
90
|
+
app_id = "#{BmcDaemonLib::Conf.app_name}/#{BmcDaemonLib::Conf.app_ver}"
|
91
91
|
headers = {
|
92
92
|
sent_at: DateTime.now.iso8601(SHOUTER_SENTAT_DECIMALS),
|
93
|
-
sent_by:
|
93
|
+
sent_by: app_id,
|
94
94
|
}
|
95
95
|
|
96
96
|
# Publish
|
97
|
-
|
97
|
+
exchange.publish(body.to_json,
|
98
98
|
routing_key: routing_key,
|
99
99
|
headers: headers,
|
100
|
-
app_id:
|
100
|
+
app_id: app_id,
|
101
101
|
content_type: "application/json",
|
102
102
|
)
|
103
103
|
end
|
104
104
|
|
105
105
|
# NewRelic instrumentation
|
106
|
-
add_transaction_tracer :
|
107
|
-
add_transaction_tracer :shout,
|
106
|
+
#add_transaction_tracer :exchange_shout, category: :task
|
107
|
+
# add_transaction_tracer :shout, category: :task
|
108
108
|
|
109
109
|
end
|
110
110
|
end
|
data/lib/pushyd.rb
CHANGED
@@ -4,13 +4,18 @@ require 'bmc-daemon-lib'
|
|
4
4
|
require "yaml"
|
5
5
|
require "json"
|
6
6
|
require "newrelic_rpm"
|
7
|
+
require "rollbar"
|
8
|
+
|
7
9
|
|
8
10
|
# Shared libs
|
9
11
|
require_relative "shared/hmac_signature"
|
10
12
|
|
11
13
|
# Project libs
|
12
14
|
require_relative "pushyd/constants"
|
13
|
-
require_relative "pushyd/endpoint"
|
14
15
|
require_relative "pushyd/proxy"
|
16
|
+
require_relative "pushyd/consumer"
|
15
17
|
require_relative "pushyd/shouter"
|
16
18
|
require_relative "pushyd/daemon"
|
19
|
+
|
20
|
+
# Init
|
21
|
+
require_relative "pushyd/initialize"
|
@@ -4,21 +4,33 @@ require 'base64'
|
|
4
4
|
module Shared
|
5
5
|
module HmacSignature
|
6
6
|
|
7
|
-
def headers_sign
|
8
|
-
|
9
|
-
unless
|
10
|
-
|
7
|
+
def headers_sign headers, config, names = ['date']
|
8
|
+
# Extract and check
|
9
|
+
return unless config.is_a? Hash
|
10
|
+
hmac_method = config[:method]
|
11
|
+
hmac_user = config[:user]
|
12
|
+
hmac_secret = config[:secret]
|
13
|
+
#log_debug "headers_sign config", config
|
14
|
+
|
15
|
+
# Check params
|
16
|
+
unless config[:method] && config[:user] && config[:secret]
|
17
|
+
log_error "headers_sign: missing method/user/secret"
|
18
|
+
return
|
19
|
+
end
|
20
|
+
|
21
|
+
# Check params
|
22
|
+
unless config[:method] == 'hmac-kong'
|
23
|
+
log_error "headers_sign: only [hmac-kong] method is supported"
|
11
24
|
return
|
12
25
|
end
|
13
26
|
|
14
27
|
# OK, lets go
|
15
|
-
|
16
|
-
|
17
|
-
log_info "headers_sign: after:", request.headers
|
28
|
+
hmac_sign_kong headers, config[:user], config[:secret], names
|
29
|
+
# log_info "headers_sign: after signing", headers
|
18
30
|
end
|
19
31
|
|
20
|
-
def headers_md5
|
21
|
-
|
32
|
+
def headers_md5 headers, payload
|
33
|
+
headers['Content-MD5'] = Digest::MD5.hexdigest(payload.to_s)
|
22
34
|
end
|
23
35
|
|
24
36
|
private
|
@@ -33,18 +45,17 @@ module Shared
|
|
33
45
|
myheaders = hmac_headers_filter headers, names
|
34
46
|
|
35
47
|
# Signe string of headers
|
36
|
-
|
37
|
-
log_debug "hmac_sign_kong #{myheaders.keys.inspect}
|
48
|
+
signature = hmac_headers_hash myheaders, client_secret
|
49
|
+
log_debug "hmac_sign_kong signed [#{signature}] from headers #{myheaders.keys.inspect}"
|
38
50
|
|
39
51
|
# Add auth header
|
40
|
-
|
41
|
-
headers['test'] = "testing123"
|
52
|
+
headers['Authorization'] = hmac_build_header(client_id, myheaders, signature)
|
53
|
+
#headers['test'] = "testing123"
|
42
54
|
|
43
55
|
# That's OK
|
44
56
|
return headers
|
45
57
|
end
|
46
58
|
|
47
|
-
|
48
59
|
def hmac_build_header client_id, myheaders, signature
|
49
60
|
sprintf 'hmac username="%s", algorithm="hmac-sha1", headers="%s", signature="%s"',
|
50
61
|
client_id,
|
data/pushyd.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
Gem::Specification.new do |spec|
|
3
3
|
# Project version
|
4
|
-
spec.version = "0.
|
4
|
+
spec.version = "0.20.0"
|
5
5
|
|
6
6
|
# Project description
|
7
7
|
spec.name = "pushyd"
|
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
# spec.add_development_dependency "pry"
|
29
29
|
|
30
30
|
# Runtime dependencies
|
31
|
-
spec.add_runtime_dependency "bmc-daemon-lib", "~> 0.
|
31
|
+
spec.add_runtime_dependency "bmc-daemon-lib", "~> 0.3.14"
|
32
32
|
spec.add_runtime_dependency "daemons"
|
33
33
|
spec.add_runtime_dependency "json"
|
34
34
|
spec.add_runtime_dependency "bunny", "~> 2.3"
|
@@ -36,4 +36,5 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.add_runtime_dependency "api-auth"
|
37
37
|
spec.add_runtime_dependency "terminal-table"
|
38
38
|
spec.add_runtime_dependency "newrelic_rpm"
|
39
|
+
spec.add_runtime_dependency "rollbar"
|
39
40
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pushyd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.20.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bruno MEDICI
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -86,14 +86,14 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
89
|
+
version: 0.3.14
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
96
|
+
version: 0.3.14
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: daemons
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,6 +192,20 @@ dependencies:
|
|
192
192
|
- - ">="
|
193
193
|
- !ruby/object:Gem::Version
|
194
194
|
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: rollbar
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :runtime
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
195
209
|
description: A nice proxy listenning to a RabbitMQ bus, repeating selected messages
|
196
210
|
in POST requests when filters match routing patterns
|
197
211
|
email: pushyd@bmconseil.com
|
@@ -210,8 +224,9 @@ files:
|
|
210
224
|
- defaults.yml
|
211
225
|
- lib/pushyd.rb
|
212
226
|
- lib/pushyd/constants.rb
|
227
|
+
- lib/pushyd/consumer.rb
|
213
228
|
- lib/pushyd/daemon.rb
|
214
|
-
- lib/pushyd/
|
229
|
+
- lib/pushyd/initialize.rb
|
215
230
|
- lib/pushyd/proxy.rb
|
216
231
|
- lib/pushyd/shouter.rb
|
217
232
|
- lib/shared/hmac_signature.rb
|
data/lib/pushyd/endpoint.rb
DELETED
@@ -1,137 +0,0 @@
|
|
1
|
-
require 'bunny'
|
2
|
-
require "securerandom"
|
3
|
-
|
4
|
-
module PushyDaemon
|
5
|
-
# Class exceptions
|
6
|
-
class EndpointConnexionContext < StandardError; end
|
7
|
-
class EndpointConnectionError < StandardError; end
|
8
|
-
class EndpointSubscribeContext < StandardError; end
|
9
|
-
class EndpointSubscribeError < StandardError; end
|
10
|
-
|
11
|
-
class Endpoint
|
12
|
-
include BmcDaemonLib::LoggerHelper
|
13
|
-
attr_reader :logger
|
14
|
-
|
15
|
-
def initialize
|
16
|
-
# Prepare logger
|
17
|
-
@logger = BmcDaemonLib::LoggerPool.instance.get :file
|
18
|
-
|
19
|
-
# Done
|
20
|
-
log_info "endpoint initialized"
|
21
|
-
end
|
22
|
-
|
23
|
-
protected
|
24
|
-
|
25
|
-
def log_message msg_way, msg_exchange, msg_key, msg_body = [], msg_attrs = {}
|
26
|
-
# Message header
|
27
|
-
info sprintf("%3s %-15s %s", msg_way, msg_exchange, msg_key)
|
28
|
-
|
29
|
-
# Body lines
|
30
|
-
if msg_body.is_a?(Enumerable) && !msg_body.empty?
|
31
|
-
body_json = JSON.pretty_generate(msg_body)
|
32
|
-
log_debug nil, body_json.lines
|
33
|
-
end
|
34
|
-
|
35
|
-
# Attributes lines
|
36
|
-
log_debug nil, msg_attrs if msg_attrs
|
37
|
-
end
|
38
|
-
|
39
|
-
# Start connexion to RabbitMQ
|
40
|
-
def connect_channel busconf
|
41
|
-
fail PushyDaemon::EndpointConnexionContext, "invalid bus host/port" unless busconf
|
42
|
-
info "connecting to bus", {
|
43
|
-
broker: busconf,
|
44
|
-
recover: AMQP_RECOVERY_INTERVAL,
|
45
|
-
heartbeat: AMQP_HEARTBEAT_INTERVAL,
|
46
|
-
prefetch: AMQP_PREFETCH
|
47
|
-
}
|
48
|
-
conn = Bunny.new busconf.to_s,
|
49
|
-
logger: @logger,
|
50
|
-
# heartbeat: :server,
|
51
|
-
automatically_recover: true,
|
52
|
-
network_recovery_interval: AMQP_RECOVERY_INTERVAL,
|
53
|
-
heartbeat_interval: AMQP_HEARTBEAT_INTERVAL
|
54
|
-
conn.start
|
55
|
-
|
56
|
-
# Create channel, prefetch only one message at a time
|
57
|
-
channel = conn.create_channel
|
58
|
-
channel.prefetch(AMQP_PREFETCH)
|
59
|
-
|
60
|
-
rescue Bunny::TCPConnectionFailedForAllHosts, Bunny::AuthenticationFailureError, AMQ::Protocol::EmptyResponseError => e
|
61
|
-
fail PushyDaemon::EndpointConnectionError, "error connecting (#{e.class})"
|
62
|
-
rescue StandardError => e
|
63
|
-
fail PushyDaemon::EndpointConnectionError, "unknow (#{e.inspect})"
|
64
|
-
else
|
65
|
-
return channel
|
66
|
-
end
|
67
|
-
|
68
|
-
# Declare or return the exchange for this topic
|
69
|
-
def channel_exchange topic
|
70
|
-
@exchanges ||= {}
|
71
|
-
@exchanges[topic] ||= @channel.topic(topic, durable: true, persistent: true)
|
72
|
-
end
|
73
|
-
|
74
|
-
# Subscribe to interesting topic/routes and bind a listenner
|
75
|
-
def channel_subscribe rule
|
76
|
-
# Check information
|
77
|
-
rule_name = rule[:name].to_s
|
78
|
-
rule_topic = rule[:topic].to_s
|
79
|
-
rule_routes = rule[:routes].to_s.split(' ')
|
80
|
-
rule_queue = "#{Conf.app_name}-#{rule[:name]}"
|
81
|
-
fail PushyDaemon::EndpointSubscribeContext, "rule [#{rule_name}] lacking topic" unless rule_topic
|
82
|
-
fail PushyDaemon::EndpointSubscribeContext, "rule [#{rule_name}] lacking routes" if rule_routes.empty?
|
83
|
-
|
84
|
-
# Create queue for this rule (remove it beforehand)
|
85
|
-
#conn.create_channel.queue_delete(rule_queue_name)
|
86
|
-
queue = @channel.queue(rule_queue, auto_delete: false, durable: true)
|
87
|
-
|
88
|
-
# Bind each route from this topic-exchange
|
89
|
-
topic_exchange = channel_exchange(rule_topic)
|
90
|
-
rule_routes.each do |route|
|
91
|
-
# Bind exchange to queue
|
92
|
-
queue.bind topic_exchange, routing_key: route
|
93
|
-
info "subscribe: bind [#{rule_topic}/#{route}] \t> #{rule_queue}"
|
94
|
-
|
95
|
-
# Add row to config table
|
96
|
-
# ["rule", "topic", "route", "relay", "queue", "description"]
|
97
|
-
@table.add_row [rule_name, rule_topic, route, rule[:relay].to_s, rule_queue, rule[:title].to_s ]
|
98
|
-
end
|
99
|
-
|
100
|
-
# Subscribe to our new queue
|
101
|
-
queue.subscribe(block: false, manual_ack: PROXY_USE_ACK, message_max: PROXY_MESSAGE_MAX) do |delivery_info, metadata, payload|
|
102
|
-
|
103
|
-
# Handle the message
|
104
|
-
handle_message rule, delivery_info, metadata, payload
|
105
|
-
|
106
|
-
end
|
107
|
-
|
108
|
-
rescue Bunny::PreconditionFailed => e
|
109
|
-
fail PushyDaemon::EndpointSubscribeError, "PreconditionFailed: [#{rule_topic}] code(#{e.channel_close.reply_code}) message(#{e.channel_close.reply_text})"
|
110
|
-
|
111
|
-
rescue StandardError => e
|
112
|
-
fail PushyDaemon::EndpointSubscribeError, "unhandled (#{e.inspect})"
|
113
|
-
|
114
|
-
end
|
115
|
-
|
116
|
-
def handle_message rule, delivery_info, metadata, payload
|
117
|
-
end
|
118
|
-
|
119
|
-
def identifier len
|
120
|
-
rand(36**len).to_s(36)
|
121
|
-
end
|
122
|
-
|
123
|
-
def format_bytes number, unit="", decimals = 0
|
124
|
-
return "Ø" if number.nil? || number.to_f.zero?
|
125
|
-
|
126
|
-
units = ["", "k", "M", "G", "T", "P" ]
|
127
|
-
index = ( Math.log(number) / Math.log(2) ).to_i / 10
|
128
|
-
converted = number.to_f / (1024 ** index)
|
129
|
-
|
130
|
-
truncated = converted.round(decimals)
|
131
|
-
return "#{truncated} #{units[index]}#{unit}"
|
132
|
-
end
|
133
|
-
|
134
|
-
private
|
135
|
-
|
136
|
-
end
|
137
|
-
end
|