pushyd 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8f1475888d98b181ea4d70fbd0568a1ea73b900a
4
+ data.tar.gz: a4f3e851e8d8698084e480a2ea94c2fd1040d5dc
5
+ SHA512:
6
+ metadata.gz: 507f389e40d4d80de6f4db4ed61c526d644cc0c0bdce04b21565c3507289421f0bda9d650f6dd4cfb3b3f9e6ebe0d491a6410781bd18de1b34fd8d9160a30375
7
+ data.tar.gz: c999e4e4bb98169092434000ceaa5aaf6facb2be792123ae56170458b732de78d2351c30883fabdd4f7ef5eb4fd45b776b823986546cc0811ea961b9d5c1f0c3
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ pkg
2
+ .bundle
3
+ .DS_Store
4
+ *.log
5
+ tmp/
6
+ log/
7
+ DOC/
8
+ .ruby-version
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,86 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ pushyd (0.0.2)
5
+ bunny
6
+ chamber
7
+ daemons
8
+ json
9
+ rest_client
10
+ terminal-table
11
+
12
+ GEM
13
+ remote: http://rubygems.org/
14
+ specs:
15
+ addressable (2.4.0)
16
+ amq-protocol (2.0.1)
17
+ ast (2.2.0)
18
+ astrolabe (1.3.1)
19
+ parser (~> 2.2)
20
+ bunny (2.2.2)
21
+ amq-protocol (>= 2.0.1)
22
+ chamber (2.9.0)
23
+ hashie (~> 3.3)
24
+ thor (~> 0.19.1)
25
+ daemons (1.2.3)
26
+ diff-lcs (1.2.5)
27
+ domain_name (0.5.20160310)
28
+ unf (>= 0.0.5, < 1.0.0)
29
+ hashie (3.4.4)
30
+ http (0.9.9)
31
+ addressable (~> 2.3)
32
+ http-cookie (~> 1.0)
33
+ http-form_data (~> 1.0.1)
34
+ http_parser.rb (~> 0.6.0)
35
+ http-cookie (1.0.2)
36
+ domain_name (~> 0.5)
37
+ http-form_data (1.0.1)
38
+ http_parser.rb (0.6.0)
39
+ json (1.8.3)
40
+ netrc (0.7.9)
41
+ parser (2.3.1.2)
42
+ ast (~> 2.2)
43
+ powerpack (0.1.1)
44
+ rainbow (2.1.0)
45
+ rake (11.1.2)
46
+ rest_client (1.8.3)
47
+ netrc (~> 0.7.7)
48
+ rspec (3.4.0)
49
+ rspec-core (~> 3.4.0)
50
+ rspec-expectations (~> 3.4.0)
51
+ rspec-mocks (~> 3.4.0)
52
+ rspec-core (3.4.4)
53
+ rspec-support (~> 3.4.0)
54
+ rspec-expectations (3.4.0)
55
+ diff-lcs (>= 1.2.0, < 2.0)
56
+ rspec-support (~> 3.4.0)
57
+ rspec-mocks (3.4.1)
58
+ diff-lcs (>= 1.2.0, < 2.0)
59
+ rspec-support (~> 3.4.0)
60
+ rspec-support (3.4.1)
61
+ rubocop (0.32.1)
62
+ astrolabe (~> 1.3)
63
+ parser (>= 2.2.2.5, < 3.0)
64
+ powerpack (~> 0.1)
65
+ rainbow (>= 1.99.1, < 3.0)
66
+ ruby-progressbar (~> 1.4)
67
+ ruby-progressbar (1.8.1)
68
+ terminal-table (1.5.2)
69
+ thor (0.19.1)
70
+ unf (0.1.4)
71
+ unf_ext
72
+ unf_ext (0.0.7.2)
73
+
74
+ PLATFORMS
75
+ ruby
76
+
77
+ DEPENDENCIES
78
+ bundler (~> 1.6)
79
+ http (~> 0.8)
80
+ pushyd!
81
+ rake
82
+ rspec
83
+ rubocop (~> 0.32.0)
84
+
85
+ BUNDLED WITH
86
+ 1.11.2
data/README.md ADDED
@@ -0,0 +1 @@
1
+ # pushyd
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+ require "bundler/gem_tasks"
3
+ require "rubygems"
4
+
5
+ require "rspec/core/rake_task"
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ # Run specs by default
9
+ desc "Run all tests"
10
+
11
+ require "rubocop/rake_task"
12
+ RuboCop::RakeTask.new(:rubocop) do |task|
13
+ task.fail_on_error = false
14
+ end
15
+
16
+ task default: [:spec, :rubocop]
data/bin/pushyd.rb ADDED
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Try to load external libs, helpers and constants
4
+ begin
5
+ require "rubygems"
6
+ require "optparse"
7
+ require 'daemons'
8
+ require 'logger'
9
+ require_relative "../lib/pushyd/config"
10
+ rescue LoadError
11
+ raise "EXITING: some basic libs were not found"
12
+ end
13
+
14
+ # Guess app root
15
+ APP_ROOT = File.expand_path(File.dirname(__FILE__) + "/../")
16
+
17
+ # Parse options and check compliance
18
+ cmd_config = nil
19
+ cmd_env = "production"
20
+ cmd_dump = false
21
+ begin
22
+ OptionParser.new do |opts|
23
+ opts.banner = "Usage: #{File.basename $PROGRAM_NAME} [options] start|stop"
24
+ opts.on("-c", "--config CONFIGFILE") { |config| cmd_config = File.expand_path(config)}
25
+ opts.on("-e", "--environment ENV") { |env| cmd_env = env }
26
+ opts.on("-d", "--dump") { cmd_dump = true }
27
+ opts.on("", "--dev") { cmd_env = "development" }
28
+ end.order!(ARGV)
29
+ rescue OptionParser::InvalidOption => e
30
+ abort "EXITING: option parser: #{e.message}"
31
+ end
32
+
33
+
34
+ # Build Chamber-based configuration from Gemspec with initial context
35
+ Config.prepare root: APP_ROOT, gemspec: "pushyd", env: cmd_env, config: cmd_config
36
+
37
+ # Display final configuration
38
+ puts "--- #{Config.name} #{Config.version}"
39
+ puts "Environment \t #{Config.env}"
40
+ puts "Config files \t #{Config.files}"
41
+ puts
42
+ puts "Log file \t #{Config[:log]}"
43
+ puts Config.dump if cmd_dump
44
+
45
+
46
+ # Run daemon
47
+ run_options = {
48
+ ontop: false,
49
+ # :dir_mode => :normal,
50
+ # :dir => File.join(root, 'amine.log'),
51
+ # :log_output => true,
52
+ :backtrace => true,
53
+ :multiple => false
54
+ }
55
+ Daemons.run_proc('pushy-daemon', run_options) do
56
+ # Load code
57
+ puts "--- loading code and logger"
58
+ require_relative "../lib/pushyd"
59
+
60
+ # Prepare logger
61
+ if Config[:log]
62
+ logger = Logger.new(Config[:log])
63
+ logger.info('Daemon starting')
64
+ end
65
+
66
+ # Start daemon
67
+ puts "--- starting"
68
+ PushyDaemon::Daemon.run(logger)
69
+ end
data/defaults.yml ADDED
@@ -0,0 +1,25 @@
1
+ # common defaults
2
+ flag: 0
3
+ bus:
4
+ host: localhost
5
+ port: 5672
6
+ user: guest
7
+ pass: guest
8
+ log: "pushyd.log"
9
+ shout:
10
+ topic: pushyd
11
+ # keys:
12
+ # - tic
13
+ # - tac
14
+ # - toe
15
+ # - created
16
+ # - updated
17
+ # - deleted
18
+ # - crunched
19
+ # rules:
20
+ # proxy_tests:
21
+ # title: All proxy tests messages
22
+ # topic: proxy
23
+ # routes: "proxy.#"
24
+ # subscribe: false
25
+ # #relay: http://requestb.in/1clzv7v1
@@ -0,0 +1,43 @@
1
+ require "chamber"
2
+
3
+ class Config
4
+ extend Chamber
5
+
6
+ class << self
7
+ attr_reader :name
8
+ attr_reader :spec
9
+ attr_reader :files
10
+ attr_reader :version
11
+ attr_reader :env
12
+ end
13
+
14
+ def self.prepare args = {}
15
+ # Context parameters
16
+ raise "config: missing root" unless (@root = args[:root])
17
+ raise "config: missing env" unless (@env = args[:env])
18
+
19
+ # Gemspec parameter
20
+ gemspec_path = "#{args[:root]}/#{args[:gemspec]}.gemspec"
21
+ raise "config: missing gemspec" unless args[:gemspec]
22
+ raise "config: missing gemspec file at #{gemspec_path}" unless File.exist?(gemspec_path)
23
+
24
+ # Load Gemspec
25
+ @spec = Gem::Specification::load gemspec_path
26
+ @name = @spec.name
27
+ @version = @spec.version
28
+ raise "config: missing name" unless @name
29
+
30
+ # Init Chamber (defaults, etc, cmdline)
31
+ @files = ["#{args[:root]}/defaults.yml"]
32
+ @files << File.expand_path("/etc/#{@name}.yml")
33
+ @files << args[:config].to_s if args[:config]
34
+
35
+ # Load configuration files
36
+ load files: @files, namespaces: { environment: @env }
37
+ end
38
+
39
+ def self.dump
40
+ self.to_hash.to_yaml
41
+ end
42
+
43
+ end
@@ -0,0 +1,21 @@
1
+ module PushyDaemon
2
+ class Daemon
3
+
4
+ def self.run(logger)
5
+ # Create a new proxy
6
+ p = Proxy.new(logger)
7
+
8
+ # Prepare subscriptions
9
+ p.prepare
10
+
11
+ # Make it listen
12
+
13
+ # Dump config table
14
+ puts p.table.to_s
15
+
16
+ # Start infinite loop
17
+ p.main
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,268 @@
1
+ require 'rest_client'
2
+ require 'bunny'
3
+ require 'yaml'
4
+ require 'json'
5
+ require 'terminal-table'
6
+
7
+ # Constants
8
+ PROXY_MESSAGE_MAX = 1
9
+ PROXY_USE_ACK = false
10
+ PROXY_SCOPE = "dev"
11
+ # PROXY_IDENT = "proxy"
12
+ # QUEUE_HOST = `hostname`.to_s.chomp
13
+ # SEPARATOR = "="*160
14
+ # ACK_PERCENT = 50
15
+
16
+
17
+ module PushyDaemon
18
+ class Proxy
19
+
20
+ attr_accessor :table
21
+
22
+ def initialize(logger)
23
+ @exchanges = {}
24
+ @logger = logger
25
+
26
+ # Init ASCII table
27
+ @table = Terminal::Table.new
28
+ @table.title = "Propagation rules"
29
+ @table.headings = ["queue binding", "topic", "route", "relay", "title"]
30
+ @table.align_column(5, :right)
31
+ end
32
+
33
+ def prepare
34
+ # Start connexion to RabbitMQ and create channel
35
+ conn = connect Config.bus
36
+ @channel = conn.create_channel
37
+ info "prepare: connected on a channel"
38
+
39
+ # Check rules
40
+ unless (Config.rules.is_a? Enumerable) && !Config.rules.empty?
41
+ abort "prepare: empty [rules] section"
42
+ end
43
+ info "prepare: found [#{Config.rules.size}] rules"
44
+
45
+ # Subsribe for each and every rule/route
46
+ Config.rules.each do |name, rule|
47
+ rule[:name] = name
48
+ channel_subscribe rule
49
+ #abort "prepare: OK"
50
+ end
51
+
52
+ # Send config table to logs
53
+ info "prepare: dumping configuration\n#{@table.to_s}"
54
+ end
55
+
56
+ def main
57
+ loop do
58
+ info "ping"
59
+ sleep(1)
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def abort message
66
+ @logger.error "ABORT: #{message}"
67
+ raise "ABORT: #{message}"
68
+ end
69
+
70
+ def info message
71
+ @logger.info message
72
+ end
73
+
74
+ def dump_rules rules
75
+
76
+ end
77
+
78
+ # Start connexion to RabbitMQ
79
+ def connect busconf
80
+ abort "connect: bus host/port not found" unless busconf.is_a? Hash
81
+
82
+ puts "connecting to #{busconf[:host]} port #{busconf[:port]}"
83
+ conn = Bunny.new host: (busconf[:host].to_s || "localhost").to_s,
84
+ port: busconf[:port].to_i,
85
+ user: busconf[:user].to_s,
86
+ pass: busconf[:pass].to_s,
87
+ heartbeat: :server
88
+ conn.start
89
+ rescue Bunny::TCPConnectionFailedForAllHosts, Bunny::AuthenticationFailureError, AMQ::Protocol::EmptyResponseError => e
90
+ abort "connect: error connecting to RabbitMQ (#{e.class})"
91
+ rescue Exception => e
92
+ abort "connect: unknow connection error (#{e.inspect})"
93
+ else
94
+ return conn
95
+ end
96
+
97
+ # Declare or return the exchange for this topic
98
+ def channel_exchange topic
99
+ @exchanges ||= {}
100
+ @exchanges[topic] ||= @channel.topic(topic, durable: true, persistent: true)
101
+ end
102
+
103
+ # Subscribe to interesting topic/routes and bind a listenner
104
+ def channel_subscribe rule
105
+ # Check information
106
+ rule_name = rule[:name].to_s
107
+ rule_topic = rule[:topic].to_s
108
+ rule_routes = rule[:routes].to_s.split(' ')
109
+ rule_queue = "#{Config.name}-#{PROXY_SCOPE}-#{rule[:name]}"
110
+ abort "subscribe: rule [#{rule_name}] lacking topic" unless rule_topic
111
+ abort "subscribe: rule [#{rule_name}] lacking routes" if rule_routes.empty?
112
+
113
+ # Create queue for this rule (remove it beforehand)
114
+ #conn.create_channel.queue_delete(rule_queue_name)
115
+ queue = @channel.queue(rule_queue, auto_delete: false, durable: true)
116
+
117
+ # Bind each route from this topic-exchange
118
+ topic_exchange = channel_exchange(rule_topic)
119
+ rule_routes.each do |route|
120
+ # Bind exchange to queue
121
+ queue.bind topic_exchange, routing_key: route
122
+ info "subscribe: bind: \t[#{rule_topic}] \t[#{route}] \t> [#{rule_queue}]"
123
+
124
+ # Add row to config table
125
+ @table.add_row [rule_name, rule_topic, route, rule[:relay].to_s, rule[:title].to_s ]
126
+ end
127
+
128
+ # Subscribe to our new queue
129
+ queue.subscribe(block: false, manual_ack: PROXY_USE_ACK, message_max: PROXY_MESSAGE_MAX) do |delivery_info, metadata, payload|
130
+
131
+ # Handle the message
132
+ handle_message rule[:name], rule, delivery_info, metadata, payload
133
+
134
+ end
135
+
136
+ rescue Bunny::PreconditionFailed => e
137
+ abort "subscribe: PreconditionFailed: [#{rule_topic}] code(#{e.channel_close.reply_code}) message(#{e.channel_close.reply_text})"
138
+ rescue Exception => e
139
+ abort "subscribe: unhandled (#{e.inspect})"
140
+
141
+ end
142
+
143
+ # Handle the reception of a message on a queue
144
+ def handle_message rule, delivery_info, metadata, payload
145
+ # Prepare data
146
+ rule_name = rule[:name]
147
+ msg_topic = delivery_info.exchange
148
+ msg_rkey = delivery_info.routing_key.force_encoding('UTF-8')
149
+ msg_headers = metadata.headers || {}
150
+
151
+ # Extract fields
152
+ data = parse payload, metadata.content_type #, rule
153
+
154
+ # Announce match
155
+ header rule_name, "<", msg_topic, msg_rkey
156
+
157
+ # Build notification payload
158
+ body = {
159
+ # received: msg_topic,
160
+ exchange: msg_topic,
161
+ route: msg_rkey,
162
+ #headers: msg_headers,
163
+ sent_at: msg_headers['sent_at'],
164
+ sent_by: msg_headers['sent_by'],
165
+ data: data,
166
+ }
167
+ pretty_body = JSON.pretty_generate(body)
168
+
169
+ # Dump body data
170
+ puts "RULE: #{rule.inspect}"
171
+ puts "APP-ID: #{metadata.app_id}"
172
+ puts "CONTENT-TYPE: #{metadata.content_type}"
173
+ puts pretty_body
174
+
175
+ # Propagate data if needed
176
+ #propagate rule[:relay], pretty_body
177
+ end
178
+
179
+ def propagate url, body
180
+ # Nothing more to do if no relay
181
+ return if url.nil? || url.empty?
182
+
183
+ # Push message to URL
184
+ puts "> POST #{url}"
185
+ response = RestClient.post url.to_s, body, :content_type => :json
186
+ puts "< #{response.body}"
187
+
188
+ rescue Exception => e
189
+ abort "propagate: #{e.message}"
190
+
191
+ end
192
+
193
+
194
+ def parse payload, content_type #, fields = []
195
+ # Force encoding (pftop...)
196
+ utf8payload = payload.force_encoding('UTF-8')
197
+
198
+ # Parse payload if content-type provided
199
+ case content_type
200
+ when "application/json"
201
+ # if fields = rule[:payload_extract]
202
+ # data = payload_extract(payload, fields)
203
+ # data_source = "extract #{fields.inspect} #{data.keys.count}k"
204
+ return JSON.parse utf8payload
205
+
206
+ when "text/plain"
207
+ return utf8payload.to_s
208
+
209
+ else
210
+ return utf8payload
211
+ end
212
+
213
+ # Handle body parse errors
214
+ rescue Encoding::UndefinedConversionError => e
215
+ abort "parse: JSON PARSE ERROR: #{e.inspect}"
216
+ return {}
217
+ end
218
+
219
+ end
220
+
221
+ end
222
+
223
+
224
+ # def prepare_shout
225
+
226
+
227
+ # # Prepare shout config
228
+ # shout_config = config[:shout]
229
+ # shout_exchange = nil
230
+ # shout_keys = []
231
+
232
+ # if shout_config.is_a? Hash
233
+ # shout_exchange = topic(channel, shout_config[:topic])
234
+ # shout_keys = shout_config[:keys] if shout_config[:keys].is_a? Array
235
+ # end
236
+
237
+ # end
238
+
239
+ # def endlessly
240
+ # # Endless loop with shout config
241
+ # begin
242
+ # loop do
243
+ # if shout_exchange
244
+ # random_string = SecureRandom.hex
245
+ # random_key = shout_keys.sample || "random"
246
+ # shout shout_exchange, [:ping, random_key, random_string], {}
247
+ # end
248
+ # sleep 1
249
+ # end
250
+ # rescue AMQ::Protocol::EmptyResponseError => e
251
+ # abort "ERROR: AMQ::Protocol::EmptyResponseError (#{e.inspect})"
252
+ # rescue Bunny::TCPConnectionFailedForAllHosts => e
253
+ # abort "ERROR: cannot connect to RabbitMQ hosts (#{e.inspect})"
254
+ # rescue Bunny::ChannelAlreadyClosed => e
255
+ # abort "ERROR: channel unexpectedly closed (#{e.inspect})"
256
+ # # sleep 1
257
+ # # retry
258
+ # rescue Bunny::PreconditionFailed => e
259
+ # abort "ERROR: precondition failed (#{e.inspect})"
260
+ # rescue Interrupt => e
261
+ # channel.close
262
+ # conn.close
263
+ # abort "QUITTING"
264
+ # end
265
+ # end
266
+
267
+ # Dump configuration
268
+ # Hashie.symbolize_keys! config
data/lib/pushyd.rb ADDED
@@ -0,0 +1,13 @@
1
+
2
+ # Global libs
3
+ require "rubygems"
4
+ require "json"
5
+ require "thread"
6
+ require "singleton"
7
+ # require "newrelic_rpm"
8
+
9
+ # Project's libs
10
+ require_relative "pushyd/config"
11
+ require_relative "pushyd/proxy"
12
+ require_relative "pushyd/daemon"
13
+
data/pushyd.gemspec ADDED
@@ -0,0 +1,38 @@
1
+ # coding: utf-8
2
+ Gem::Specification.new do |spec|
3
+ # Project version
4
+ spec.version = "0.0.2"
5
+
6
+ # Project description
7
+ spec.name = "pushyd"
8
+ spec.authors = ["Bruno MEDICI"]
9
+ spec.email = "pushyd@bmconseil.com"
10
+ spec.description = "(description to be written)"
11
+ spec.summary = "(summary to be written)"
12
+ spec.homepage = "http://github.com/bmedici/pushyd"
13
+ spec.licenses = ["MIT"]
14
+ spec.date = Time.now.strftime("%Y-%m-%d")
15
+
16
+ # List files and executables
17
+ spec.files = `git ls-files -z`.split("\x0").reject{ |f| f == "dashboard.png"}
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+ spec.required_ruby_version = ">= 2.2"
21
+
22
+ # Development dependencies
23
+ spec.add_development_dependency "bundler", "~> 1.6"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "http", "~> 0.8"
27
+ spec.add_development_dependency "rubocop", "~> 0.32.0"
28
+ # spec.add_development_dependency "pry"
29
+
30
+ # Runtime dependencies
31
+ spec.add_runtime_dependency "daemons"
32
+ spec.add_runtime_dependency "chamber"
33
+ spec.add_runtime_dependency "json"
34
+ spec.add_runtime_dependency "bunny"
35
+ spec.add_runtime_dependency "rest_client"
36
+ spec.add_runtime_dependency "terminal-table"
37
+ # spec.add_runtime_dependency "newrelic_rpm"
38
+ end
metadata ADDED
@@ -0,0 +1,210 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pushyd
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Bruno MEDICI
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-06-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
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: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
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: http
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.8'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.8'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.32.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.32.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: daemons
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
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: chamber
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: json
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: bunny
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rest_client
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: terminal-table
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description: "(description to be written)"
168
+ email: pushyd@bmconseil.com
169
+ executables:
170
+ - pushyd.rb
171
+ extensions: []
172
+ extra_rdoc_files: []
173
+ files:
174
+ - ".gitignore"
175
+ - Gemfile
176
+ - Gemfile.lock
177
+ - README.md
178
+ - Rakefile
179
+ - bin/pushyd.rb
180
+ - defaults.yml
181
+ - lib/pushyd.rb
182
+ - lib/pushyd/config.rb
183
+ - lib/pushyd/daemon.rb
184
+ - lib/pushyd/proxy.rb
185
+ - pushyd.gemspec
186
+ homepage: http://github.com/bmedici/pushyd
187
+ licenses:
188
+ - MIT
189
+ metadata: {}
190
+ post_install_message:
191
+ rdoc_options: []
192
+ require_paths:
193
+ - lib
194
+ required_ruby_version: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: '2.2'
199
+ required_rubygems_version: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ requirements: []
205
+ rubyforge_project:
206
+ rubygems_version: 2.5.1
207
+ signing_key:
208
+ specification_version: 4
209
+ summary: "(summary to be written)"
210
+ test_files: []