pushyd 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bef5122c9c7a8a4276bc0e1f735c48b65b88f156
4
- data.tar.gz: 8620fcd2277aafc9ff97c6c65ec4abe25a6f5339
3
+ metadata.gz: deac6c7be88fd0fe05c8afa55880aa29e6c4212d
4
+ data.tar.gz: 4f6a4226355bbee4a76bb489867f0b000d3455ed
5
5
  SHA512:
6
- metadata.gz: dabd44f13d11e6167bb96b1e4c3d5c044bb0394ee386b3fe6ad84882339a518cf941d6f21aaab79090decd982511cbb1b1fe50ce5df124d70ee8d0487000a945
7
- data.tar.gz: dc9779dfd1b20506840ccc799dbe5f8cac4d43daa30634ad4067a32a5a71b11b03dbdecdf4aa3a2075ba02195a6e40994da125cfb3208b8d234d4e2c6d765e38
6
+ metadata.gz: 646e19080f09c51c448189dbe5743a17a5be869670220ce740dd16d1f11ea49f060e8627ffe7ff8c83f61f21cc8d086ee3795bcdf0fce8594c2b639bc5006ffb
7
+ data.tar.gz: b707e637e0bd0e27acfd71f32c2b5db5caf146429fc1f3b9802facfe415242f0bc0222d6fb6d6a0f63ded5c9ba86b37736e9944fb2e63eb73df93a09a9c14b8f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pushyd (0.2.4)
4
+ pushyd (0.3.0)
5
5
  bunny
6
6
  chamber
7
7
  daemons
data/bin/pushyd CHANGED
@@ -39,8 +39,7 @@ begin
39
39
  puts "--- #{Conf.name} #{Conf.version}"
40
40
  puts "Environment \t #{Conf.env}"
41
41
  puts "Config files \t #{Conf.files}"
42
- puts
43
- puts "Log file \t #{Conf[:log]}"
42
+ puts "Loging to file \t #{Conf[:log]}"
44
43
  puts Conf.dump if cmd_dump
45
44
 
46
45
  rescue OptionParser::InvalidOption => e
@@ -55,9 +54,6 @@ end
55
54
  # Run daemon
56
55
  run_options = {
57
56
  ontop: false,
58
- # :dir_mode => :normal,
59
- # :dir => File.join(root, 'amine.log'),
60
- # :log_output => true,
61
57
  :backtrace => true,
62
58
  :multiple => false
63
59
  }
@@ -67,6 +63,6 @@ Daemons.run_proc('pushy-daemon', run_options) do
67
63
  require_relative "../lib/pushyd"
68
64
 
69
65
  # Start daemon
70
- puts "--- starting"
66
+ puts "--- starting daemon"
71
67
  PushyDaemon::Daemon.run
72
68
  end
data/defaults.yml CHANGED
@@ -5,9 +5,12 @@ bus:
5
5
  port: 5672
6
6
  user: guest
7
7
  pass: guest
8
- log: "pushyd.log"
8
+
9
+ log: null
10
+
9
11
  shout:
10
12
  topic: pushyd
13
+ period: 2
11
14
  # keys:
12
15
  # - tic
13
16
  # - tac
data/lib/pushyd/conf.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require "chamber"
2
2
 
3
3
  module PushyDaemon
4
-
5
4
  class ConfigMissingParameter < StandardError; end
6
5
  class ConfigParseError < StandardError; end
7
6
 
@@ -3,13 +3,11 @@ WAY_OUT = "SENT"
3
3
  WAY_IN = "RECD"
4
4
  WAY_POST = "POST"
5
5
 
6
-
7
6
  # Constants: proxy
8
7
  PROXY_MESSAGE_MAX = 1
9
8
  PROXY_USE_ACK = false
10
9
  PROXY_SCOPE = "dev"
11
10
 
12
-
13
11
  # Constants: logger
14
12
  LOG_COL_ID = 6
15
13
  LOG_TRIM_LINE = 200
@@ -18,4 +16,3 @@ LOG_FORMAT_MESSAGE = "%-6s"
18
16
  LOG_NEWLINE = "\n"
19
17
  LOG_INDENT = "\t"
20
18
  LOG_ROTATION = "daily"
21
-
data/lib/pushyd/daemon.rb CHANGED
@@ -14,14 +14,8 @@ module PushyDaemon
14
14
  # Start infinite loop
15
15
  s.shout
16
16
 
17
- rescue Errno::EACCES => e
18
- #logger.error "ABORT #{e.class}: #{e.message}"
19
- abort "ABORT #{e.class}: #{e.message}"
20
-
21
- rescue Exception => e
22
- #logger.error "ABORT #{e.class}: #{e.message}"
23
- abort "ABORT #{e.class}: #{e.message}"
24
-
17
+ rescue Errno::EACCES, Exception => e
18
+ abort "EXITING #{e.class}: #{e.message}"
25
19
  end
26
20
 
27
21
  end
@@ -2,7 +2,6 @@ require 'bunny'
2
2
  require 'securerandom'
3
3
 
4
4
  module PushyDaemon
5
-
6
5
  class EndpointConnexionContext < StandardError; end
7
6
  class EndpointConnectionError < StandardError; end
8
7
  class EndpointSubscribeContext < StandardError; end
@@ -17,17 +16,20 @@ module PushyDaemon
17
16
  # Create the logger
18
17
  @logger = PushyLogger.new(logfile, LOG_ROTATION)
19
18
  @logger.add Logger::INFO, "starting #{self.class.name.to_s}"
19
+
20
+ # Declare we're now logging
21
+ puts "#{self.class} logging to #{logfile}"
20
22
  end
21
23
 
22
24
  protected
23
25
 
24
- def error message
25
- @logger.add Logger::ERROR, "#{self.class}: #{message}"
26
+ def error message, lines = {}
27
+ @logger.add Logger::ERROR, "#{self.class}: #{message}", lines
26
28
  #raise "ABORT #{self.class}: #{message}"
27
29
  end
28
30
 
29
- def info message
30
- @logger.add Logger::INFO, "#{self.class}: #{message}"
31
+ def info message, lines = {}
32
+ @logger.add Logger::INFO, "#{self.class}: #{message}", lines
31
33
  end
32
34
 
33
35
  def message params = {}
@@ -52,8 +54,9 @@ module PushyDaemon
52
54
  end
53
55
 
54
56
  # Body (split in lines to log them separately)
55
- unless (params[:body].nil? || params[:body].empty?)
56
- JSON.pretty_generate(params[:body]).each_line do |line|
57
+ if params[:body] && params[:body].is_a?(Enumerable)
58
+ body_json = JSON.pretty_generate(params[:body])
59
+ body_json.each_line do |line|
57
60
  lines << line.rstrip
58
61
  end
59
62
  end
@@ -64,23 +67,27 @@ module PushyDaemon
64
67
  end
65
68
 
66
69
  # Start connexion to RabbitMQ
67
- def connect busconf
70
+ def connect_channel busconf
68
71
  raise PushyDaemon::EndpointConnexionContext, "invalid bus host/port" unless (busconf.is_a? Hash) &&
69
72
  busconf[:host] && busconf[:port]
70
73
 
71
- puts "connecting to #{busconf[:host]} port #{busconf[:port]}"
74
+ info "connecting to #{busconf[:host]} port #{busconf[:port]}"
72
75
  conn = Bunny.new host: (busconf[:host].to_s || "localhost").to_s,
73
76
  port: busconf[:port].to_i,
74
77
  user: busconf[:user].to_s,
75
78
  pass: busconf[:pass].to_s,
76
79
  heartbeat: :server
77
80
  conn.start
81
+
82
+ # Create channel
83
+ channel = conn.create_channel
84
+
78
85
  rescue Bunny::TCPConnectionFailedForAllHosts, Bunny::AuthenticationFailureError, AMQ::Protocol::EmptyResponseError => e
79
86
  raise PushyDaemon::EndpointConnectionError, "error connecting (#{e.class})"
80
87
  rescue Exception => e
81
88
  raise PushyDaemon::EndpointConnectionError, "unknow (#{e.inspect})"
82
89
  else
83
- return conn
90
+ return channel
84
91
  end
85
92
 
86
93
  # Declare or return the exchange for this topic
data/lib/pushyd/proxy.rb CHANGED
@@ -20,9 +20,8 @@ module PushyDaemon
20
20
  @table.align_column(5, :right)
21
21
 
22
22
  # Start connexion to RabbitMQ and create channel
23
- conn = connect Conf.bus
24
- @channel = conn.create_channel
25
- info "connected on a channel"
23
+ @channel = connect_channel Conf.bus
24
+ info "channel connected"
26
25
 
27
26
  # Check config
28
27
  config_rules = Conf[:rules]
@@ -39,7 +38,8 @@ module PushyDaemon
39
38
  end
40
39
 
41
40
  # Send config table to logs
42
- info "dumping configuration\n#{@table.to_s}"
41
+ table_lines = @table.to_s.lines
42
+ info "initialized with configuration:", table_lines
43
43
 
44
44
  rescue Bunny::TCPConnectionFailedForAllHosts => e
45
45
  error "ERROR: cannot connect to RabbitMQ hosts (#{e.inspect})"
@@ -100,7 +100,6 @@ module PushyDaemon
100
100
 
101
101
  rescue Exception => e
102
102
  error "propagate: #{e.message}"
103
-
104
103
  end
105
104
 
106
105
 
@@ -121,11 +120,11 @@ module PushyDaemon
121
120
  return utf8payload
122
121
  end
123
122
 
124
- # Handle body parse errors
125
- rescue Encoding::UndefinedConversionError => e
126
- error "parse: JSON PARSE ERROR: #{e.inspect}"
127
- return {}
128
- end
129
-
123
+ # Handle body parse errors
124
+ rescue Encoding::UndefinedConversionError => e
125
+ error "parse: JSON PARSE ERROR: #{e.inspect}"
126
+ return {}
130
127
  end
128
+
129
+ end
131
130
  end
@@ -25,12 +25,10 @@ class PushyLogger < Logger
25
25
  def add level, message, lines = {}
26
26
  level ||= Logger::DEBUG
27
27
 
28
- prefix = " | "
29
-
30
28
  if lines.is_a? Hash
31
- output = build_from_hash prefix, lines
29
+ output = build_from_hash lines
32
30
  elsif lines.is_a? Array
33
- output = build_from_array prefix, lines
31
+ output = build_from_array lines
34
32
  else
35
33
  output = []
36
34
  end
@@ -44,17 +42,19 @@ class PushyLogger < Logger
44
42
 
45
43
  protected
46
44
 
47
- def build_from_array prefix, lines
45
+ def trim_line line
46
+ line.to_s.rstrip.strip[0..LOG_TRIM_LINE]
47
+ end
48
+
49
+ def build_from_array lines
48
50
  lines.map do |value|
49
- text = value.to_s[0..LOG_TRIM_LINE]
50
- "#{prefix}#{text}"
51
+ "#{LOG_INDENT}#{trim_line(value)}"
51
52
  end
52
53
  end
53
54
 
54
- def build_from_hash prefix, lines
55
+ def build_from_hash lines
55
56
  lines.map do |name, value|
56
- text = value.to_s.strip[0..LOG_TRIM_LINE]
57
- "#{prefix}#{name}: #{text}"
57
+ "#{LOG_INDENT}#{name}: #{trim_line(value)}"
58
58
  end
59
59
  end
60
60
 
@@ -2,12 +2,11 @@ require 'yaml'
2
2
  require 'json'
3
3
 
4
4
  module PushyDaemon
5
-
6
- class ShouterResponseError < StandardError; end
7
- class ShouterChannelClosed < StandardError; end
8
- class ShouterPreconditionFailed < StandardError; end
9
- class ShouterInterrupted < StandardError; end
10
- class EndpointTopicContext < StandardError; end
5
+ class ShouterResponseError < StandardError; end
6
+ class ShouterChannelClosed < StandardError; end
7
+ class ShouterPreconditionFailed < StandardError; end
8
+ class ShouterInterrupted < StandardError; end
9
+ class EndpointTopicContext < StandardError; end
11
10
 
12
11
  class Shouter < Endpoint
13
12
 
@@ -19,25 +18,24 @@ module PushyDaemon
19
18
  @keys = []
20
19
 
21
20
  # Start connexion to RabbitMQ and create channel
22
- conn = connect Conf.bus
23
- @channel = conn.create_channel
24
- info "connected on a channel"
21
+ @channel = connect_channel Conf.bus
22
+ info "channel connected"
25
23
 
26
24
  # Check config
27
25
  config_shout = Conf[:shout]
28
- if (config_shout.is_a? Enumerable) && !config_shout.empty?
29
- @keys = config_shout[:keys] if config_shout[:keys].is_a? Array
30
- @topic = config_shout[:topic]
31
-
32
- info "found topic: #{@topic}"
33
- info "found keys: #{@keys.join(', ')}"
34
- else
35
- error "prepare: empty [shout] section"
26
+ if config_shout.empty? || (!config_shout.is_a? Enumerable)
27
+ abort "prepare: empty [shout] section"
36
28
  end
37
29
 
30
+ # Extract information
31
+ @keys = config_shout[:keys] if config_shout[:keys].is_a? Array
32
+ @topic = config_shout[:topic]
33
+ @period = config_shout[:period] || 0
34
+
38
35
  # Create exchange
39
36
  raise PushyDaemon::EndpointTopicContext unless @topic
40
37
  @exchange = @channel.topic(@topic, durable: true, persistent: true)
38
+ info "initialized with parameters:", {topic: @topic, period: @period, keys: @keys}
41
39
 
42
40
  rescue Bunny::TCPConnectionFailedForAllHosts => e
43
41
  error "ERROR: cannot connect to RabbitMQ hosts (#{e.inspect})"
@@ -51,7 +49,7 @@ module PushyDaemon
51
49
  random_key = @keys.sample || "random"
52
50
  channel_shout [:ping, random_key, random_string], {}
53
51
  end
54
- sleep 1
52
+ sleep @period
55
53
  end
56
54
  rescue AMQ::Protocol::EmptyResponseError => e
57
55
  raise PushyDaemon::ShouterResponseError, "#{e.class} (#{e.inspect})"
@@ -88,7 +86,6 @@ module PushyDaemon
88
86
  app_id: Conf.name,
89
87
  content_type: "application/json",
90
88
  )
91
-
92
89
  end
93
90
 
94
91
  end
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.2.4"
4
+ spec.version = "0.3.0"
5
5
 
6
6
  # Project description
7
7
  spec.name = "pushyd"
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.2.4
4
+ version: 0.3.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-06-06 00:00:00.000000000 Z
11
+ date: 2016-06-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -183,7 +183,6 @@ files:
183
183
  - lib/pushyd/constants.rb
184
184
  - lib/pushyd/daemon.rb
185
185
  - lib/pushyd/endpoint.rb
186
- - lib/pushyd/proxy.orig.rb
187
186
  - lib/pushyd/proxy.rb
188
187
  - lib/pushyd/pushy_logger.rb
189
188
  - lib/pushyd/shouter.rb
@@ -1,198 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'terminal-table'
3
- require 'hashie'
4
- require 'securerandom'
5
-
6
- # Log output
7
- def header rule, sign, topic, route
8
- puts
9
- puts SEPARATOR
10
- puts sprintf "%s | %-20s %1s %-10s | %s",
11
- DateTime.now.iso8601, rule, sign, topic, route
12
- puts SEPARATOR
13
- end
14
-
15
-
16
- def extract ctype, payload, fields = []
17
- # Force encoding (pftop...)
18
- utf8payload = payload.force_encoding('UTF-8')
19
-
20
- # Parse payload if content-type provided
21
- case ctype
22
- when "application/json"
23
- # if fields = rule[:payload_extract]
24
- # data = payload_extract(payload, fields)
25
- # data_source = "extract #{fields.inspect} #{data.keys.count}k"
26
- return JSON.parse utf8payload
27
-
28
- when "text/plain"
29
- return utf8payload.to_s
30
-
31
- else
32
- return utf8payload
33
-
34
- end
35
-
36
- # Handle body parse errors
37
- rescue Encoding::UndefinedConversionError => e
38
- puts "\t JSON PARSE ERROR: #{e.inspect}"
39
- return {}
40
-
41
- end
42
-
43
-
44
- # def payload_extract payload, fields = []
45
- # new_payload = payload.force_encoding('UTF-8')
46
- # parsed = JSON.parse new_payload
47
-
48
- # rescue Encoding::UndefinedConversionError => e
49
- # puts "\t JSON PARSE ERROR: #{e.inspect}"
50
- # return {}
51
-
52
- # else
53
- # return parsed
54
- # end
55
-
56
-
57
-
58
- # def handle_message rule_name, rule, delivery_info, metadata, payload
59
- # # Prepare data
60
- # msg_topic = delivery_info.exchange
61
- # msg_rkey = delivery_info.routing_key.force_encoding('UTF-8')
62
- # msg_headers = metadata.headers || {}
63
-
64
- # # Extract fields
65
- # data = extract metadata.content_type, payload, rule
66
-
67
- # # Announce match
68
- # header rule_name, "<", msg_topic, msg_rkey
69
-
70
- # # Build notification payload
71
- # body = {
72
- # # received: msg_topic,
73
- # exchange: msg_topic,
74
- # route: msg_rkey,
75
- # #headers: msg_headers,
76
- # sent_at: msg_headers['sent_at'],
77
- # sent_by: msg_headers['sent_by'],
78
- # data: data,
79
- # }
80
- # pretty_body = JSON.pretty_generate(body)
81
-
82
- # # Dump body data
83
- # puts "RULE: #{rule.inspect}"
84
- # puts "APP-ID: #{metadata.app_id}"
85
- # puts "CONTENT-TYPE: #{metadata.content_type}"
86
- # puts pretty_body
87
-
88
- # # Propagate data if needed
89
- # propagate rule[:relay], pretty_body
90
- # end
91
-
92
- def topic channel, name
93
- @topics ||= {}
94
- @topics[name] ||= channel.topic(name, durable: true, persistent: true)
95
- end
96
-
97
- def shout exchange, keys, body = {}
98
- # Add timestamp
99
- headers = {
100
- sent_at: DateTime.now.iso8601,
101
- sent_by: PROXY_IDENT
102
- }
103
- exchange_name = exchange.name
104
-
105
- # Prepare key and data
106
- routing_key = keys.unshift(exchange_name).join('.')
107
- # payload = data
108
-
109
- # Announce shout
110
- header "SHOUT", ">", exchange_name, routing_key
111
- puts JSON.pretty_generate(body) unless body.empty?
112
-
113
- # Publish
114
- exchange.publish(body.to_json,
115
- routing_key: routing_key,
116
- headers: headers,
117
- app_id: "contributor",
118
- content_type: "application/json",
119
- )
120
-
121
- end
122
-
123
-
124
- # Init ASCII table
125
- config_table = Terminal::Table.new
126
- config_table.title = "Message propagation rules"
127
- config_table.headings = ["queue binding", "topic", "route", "relay", "title"]
128
- config_table.align_column(5, :right)
129
-
130
-
131
- # Bind every topic
132
- config[:rules].each do |rule_name, rule|
133
- # Extract information
134
- catch_subscribe = rule[:subscribe] || true
135
- catch_topic = rule[:topic].to_s
136
- catch_routes = rule[:routes].to_s.split(' ')
137
-
138
- if catch_topic.empty? || catch_routes.empty?
139
- abort "rule [#{rule_name}] is invalid: missing topic / routes"
140
- end
141
-
142
- # Build / attach to queue
143
- rule_queue_name = "#{PROXY_IDENT}-#{QUEUE_HOST}-#{rule_name}"
144
-
145
- begin
146
- # Bind to this topic if not already done
147
- listen_exchange = topic(channel, catch_topic)
148
-
149
- # Pour this into a queue
150
- queue = channel.queue(rule_queue_name, auto_delete: false, durable: true)
151
-
152
- # Bind to these events on each route
153
- catch_routes.each do |route|
154
- # Bind with this routing key
155
- queue.bind listen_exchange, routing_key: route
156
- puts "BIND \t[#{rule_queue_name}] to [#{catch_topic}] / [#{route}] (subscribe: #{catch_subscribe})"
157
-
158
- # Add row to table
159
- config_table.add_row [rule_queue_name, catch_topic, route, rule[:relay].to_s, rule[:title].to_s ]
160
- end
161
-
162
- end
163
-
164
-
165
- # Subscribe
166
-
167
- queue.subscribe(block: false, manual_ack: SUB_USE_ACK, message_max: SUB_MSG_MAX) do |delivery_info, metadata, payload|
168
-
169
- # Handle the message
170
- handle_message rule_name, rule, delivery_info, metadata, payload
171
-
172
- # Ack the msg
173
- # puts "> #{delivery_info.delivery_tag}: nack"
174
- # channel.nack(delivery_info.delivery_tag)
175
-
176
- # if !SUB_USE_ACK
177
- # puts "> #{delivery_info.delivery_tag}: no ack"
178
- # elsif (100*rand) <= ACK_PERCENT
179
- # channel.ack(delivery_info.delivery_tag)
180
- # puts "> #{delivery_info.delivery_tag}: ACKED"
181
- # else
182
- # channel.nack(delivery_info.delivery_tag)
183
- # puts "> #{delivery_info.delivery_tag}: NOT_ACKED"
184
- # end
185
-
186
- end
187
-
188
- # End of loop
189
- end
190
-
191
-
192
- # Display config and susbcribe to queue
193
- puts config_table
194
-
195
-
196
-
197
- puts
198
- puts "ENDED"