barnyard_ccfeeder 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use ruby-1.9.3-p125@barnyard
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in barnyard_ccfeeder.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Jon Gillies
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # BarnyardCcfeeder
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'barnyard_ccfeeder'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install barnyard_ccfeeder
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/barnyard_ccfeeder/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Jon Gillies"]
6
+ gem.email = ["supercoder@gmail.com"]
7
+
8
+ gem.description = %q{Feeds the Cache Cow}
9
+ gem.summary = %q{REST API to the Cache Cow}
10
+
11
+ gem.homepage = "https://github.com/jongillies/barnyard/tree/master/barnyard_ccfeeder"
12
+
13
+ gem.rubyforge_project = "barnyard_ccfeeder"
14
+
15
+ gem.files = `git ls-files`.split($\)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.name = "barnyard_ccfeeder"
19
+ gem.require_paths = ["lib"]
20
+ gem.version = BarnyardCcfeeder::VERSION
21
+
22
+ # specify any dependencies here; for example:
23
+ gem.add_development_dependency "rspec"
24
+ gem.add_runtime_dependency "aws-sdk"
25
+ gem.add_runtime_dependency "logger"
26
+ gem.add_runtime_dependency "rest-client"
27
+ gem.add_runtime_dependency "crack"
28
+ gem.add_runtime_dependency "json"
29
+
30
+ end
@@ -0,0 +1,353 @@
1
+ require "barnyard_ccfeeder/version"
2
+ require "yaml"
3
+ require "logger"
4
+ require "rest-client"
5
+ require "crack"
6
+
7
+ module BarnyardCcfeeder
8
+ YAML::ENGINE.yamler = 'syck'
9
+
10
+ class CacheCow
11
+
12
+ CACHE_TIME = 4
13
+ RETRY_INTERVAL = 10
14
+ MAX_RETRIES = 3 #0 * 24 * 60 * 60 / RETRY_INTERVAL # retry for 30 days max.
15
+
16
+ attr_reader :crops_cache, :crops_time,
17
+ :crops_by_crop_number_cache,
18
+ :subscribers_cache, :subscribers_time,
19
+ :subscriptions_cache, :subscriptions_time
20
+
21
+ def initialize(args)
22
+
23
+
24
+ @debug = args.fetch(:debug) { false }
25
+ @log = args.fetch(:logger) { Logger.new(STDOUT) }
26
+
27
+ @secret_key = args.fetch(:secret_key) { "" }
28
+ @url = args.fetch(:url) { raise "You must provide :url" }
29
+
30
+ @max_retries = args.fetch(:max_retries) { MAX_RETRIES }
31
+ @retry_interval = args.fetch(:retry_interval) { RETRY_INTERVAL }
32
+ @cache_time = args.fetch(:cache_time) { CACHE_TIME }
33
+
34
+ @resource = RestClient::Resource.new @url
35
+
36
+ @crops_time = Time.now
37
+ @subscribers_time = Time.now
38
+ @subscriptions_time = Time.now
39
+
40
+ @crops_by_crop_number_cache = Hash.new
41
+
42
+ @connected = false
43
+ @retries = 0
44
+
45
+ while !@connected && (@retries < @max_retries)
46
+ @retries += 1
47
+ begin
48
+ # Try and load the crops to make sure we have a connection
49
+ # YAML::ENGINE.yamler = 'syck'
50
+ Crack::JSON.parse(@resource["crops.json"].get)
51
+ @connected = true
52
+ rescue
53
+ @log.fatal "(#{@retries}/#{@max_retries}) Unable to obtain connection to #{@url}/crops.json"
54
+ sleep 2
55
+ end
56
+ end
57
+
58
+ load_crops
59
+ load_subscribers
60
+ load_subscriptions
61
+
62
+ end
63
+
64
+ def load_crops
65
+ begin
66
+ # YAML::ENGINE.yamler = 'syck'
67
+ crops = Crack::JSON.parse(@resource["crops.json"].get)
68
+
69
+ @log.debug "Getting #{@url}/crops.json"
70
+
71
+ @crops_cache = Hash.new
72
+
73
+ crops.each do |crop|
74
+ @crops_cache[crop["id"]] = crop
75
+ @crops_by_crop_number_cache[crop['crop_number']] = crop
76
+ end
77
+
78
+ @crops_time = Time.now
79
+
80
+ rescue
81
+ @log.warn "Unable to get crops.json, using cached copy"
82
+ end
83
+
84
+ end
85
+
86
+ def load_subscribers
87
+ begin
88
+ # YAML::ENGINE.yamler = 'syck'
89
+ subscribers = Crack::JSON.parse(@resource["subscribers.json"].get)
90
+
91
+ @log.debug "Getting #{@url}/subscribers.json"
92
+
93
+ @subscribers_cache = Hash.new
94
+
95
+ subscribers.each do |subscriber|
96
+ @subscribers_cache[subscriber['id']] = subscriber
97
+ end
98
+
99
+ @subscribers_time = Time.now
100
+
101
+ rescue
102
+ @log.warn "Unable to get subscribers.json, using cached copy"
103
+ end
104
+ end
105
+
106
+ def load_subscriptions
107
+ begin
108
+ # YAML::ENGINE.yamler = 'syck'
109
+ subscriptions = Crack::JSON.parse(@resource["subscriptions.json"].get)
110
+
111
+ @log.debug "Getting #{@url}/subscriptions.json"
112
+
113
+ @subscriptions_cache = Hash.new
114
+
115
+ self.crops if @crops_cache.empty?
116
+ self.subscribers if @subscribers_cache.empty?
117
+
118
+ subscriptions.each do |subscription|
119
+ subscription['crop'] = @crops_cache[subscription['crop_id']]
120
+ subscription['subscriber'] = @subscribers_cache[subscription['subscriber_id']]
121
+ @subscriptions_cache[subscription['id']] = subscription
122
+ end
123
+
124
+ @subscriptions_time = Time.now
125
+
126
+ rescue
127
+ @log.warn "Unable to get subscriptions.json, using cached copy"
128
+ end
129
+
130
+ end
131
+
132
+ def crops_by_crop_number
133
+
134
+ if (@crops_time + CACHE_TIME) > Time.now
135
+ @log.debug "Using cached #{@url}/crops.json"
136
+ return @crops_by_crop_number_cache
137
+ end
138
+
139
+ load_crops
140
+ return @crops_by_crop_number_cache
141
+
142
+ end
143
+
144
+ def crops
145
+
146
+ if (@crops_time + CACHE_TIME) > Time.now
147
+ @log.debug "Using cached #{@url}/crops.json"
148
+ return @crops_cache
149
+ end
150
+
151
+ load_crops
152
+ return @crops_cache
153
+
154
+ end
155
+
156
+ def subscribers
157
+
158
+ if (@subscribers_time + CACHE_TIME) > Time.now
159
+ @log.debug "Using cached #{@url}/subscribers.json"
160
+ return @subscribers_cache
161
+ end
162
+
163
+ load_subscribers
164
+ return @subscribers_cache
165
+
166
+ end
167
+
168
+ def subscriptions
169
+
170
+ if (@subscriptions_time + CACHE_TIME) > Time.now
171
+ @log.debug "Using cached #{@url}/subscriptions.json"
172
+ return @subscriptions_cache
173
+ end
174
+
175
+ load_subscriptions
176
+ return @subscriptions_cache
177
+
178
+ end
179
+
180
+ def subscribed?(subscriber_id, crop_number)
181
+
182
+ @subscriptions_cache.each do |id, subscription|
183
+ puts "subscriber_id: #{id}"
184
+
185
+ if subscription["subscriber_id"] == subscriber_id && subscription["crop"]["crop_number"] == crop_number
186
+ return true
187
+ end
188
+ end
189
+ return false
190
+
191
+ end
192
+
193
+ # a "change" is detected by the harvester
194
+ def push_change(queued_at, harvester_uuid, change_uuid, crop_number, primary_key, transaction_type, value, old_value)
195
+
196
+ data = Hash.new
197
+
198
+ data['harvester_uuid'] = harvester_uuid
199
+ data['crop_number'] = crop_number
200
+ data['queue_time'] = queued_at
201
+ data['primary_key'] = primary_key
202
+
203
+ begin
204
+ # YAML::ENGINE.yamler = 'syck'
205
+ data['previous_value'] = old_value
206
+ rescue Exception => e
207
+ data['previous_value'] = ""
208
+ end
209
+
210
+ begin
211
+ # YAML::ENGINE.yamler = 'syck'
212
+ data['current_value'] = value
213
+ rescue Exception => e
214
+ data['current_value'] = ""
215
+ end
216
+
217
+ data['uuid'] = change_uuid
218
+ data['transaction_type'] = transaction_type
219
+
220
+ change = Hash.new
221
+ change["change"] = data
222
+
223
+ return deliver("changes", change)
224
+
225
+ end
226
+
227
+ # a "transaction" is sent to a subscriber by the farmer based on the "change"
228
+ def push_transaction(subscription_id, queued_at, change_uuid, transaction_uuid, crop_number, primary_key, transaction_type, value, old_value)
229
+
230
+ data = Hash.new
231
+
232
+ data['queue_time'] = queued_at
233
+ data['change_uuid'] = change_uuid
234
+ data['uuid'] = transaction_uuid
235
+
236
+ transaction = Hash.new
237
+ transaction["transaction"] = data
238
+
239
+ return deliver("transactions", transaction)
240
+
241
+ end
242
+
243
+ def push_delivery_status(queued_at, delivery_uuid, transaction_uuid, endpoint_response_code, endpoint_response_header, endpoint_response_data, endpoint_response_date)
244
+
245
+ data = Hash.new
246
+
247
+ data['queue_time'] = queued_at
248
+ data['uuid'] = delivery_uuid
249
+ data['transaction_uuid'] = transaction_uuid
250
+ data['endpoint_response_code'] = endpoint_response_code
251
+ data['endpoint_response_header'] = endpoint_response_header
252
+ data['endpoint_response_data'] = endpoint_response_data
253
+ data['endpoint_response_date'] = endpoint_response_date
254
+
255
+ delivery = Hash.new
256
+ delivery["delivery"] = data
257
+
258
+ return deliver("deliveries", delivery)
259
+
260
+ end
261
+
262
+ def push_harvester_stats(harvester_uuid, crop_number, began_at, ended_at, total_records, number_of_changes, number_of_adds, number_of_deletes)
263
+
264
+ data = Hash.new
265
+
266
+ data['uuid'] = harvester_uuid
267
+ data['crop_number'] = crop_number
268
+ data['began_at'] = began_at
269
+ data['ended_at'] = ended_at
270
+ data['total_records'] = total_records
271
+ data['number_of_changes'] = number_of_changes
272
+ data['number_of_adds'] = number_of_adds
273
+ data['number_of_deletes'] = number_of_deletes
274
+
275
+ harvest = Hash.new
276
+ harvest["harvest"] = data
277
+
278
+ return deliver("harvests", harvest)
279
+
280
+ end
281
+
282
+ # private
283
+
284
+ def calc(secret_key, payload)
285
+
286
+ digest = OpenSSL::Digest::Digest.new('sha1')
287
+
288
+ sig = OpenSSL::HMAC.hexdigest(digest, secret_key, payload)
289
+
290
+ return sig
291
+
292
+ end
293
+
294
+ def deliver(path, data)
295
+
296
+ raw_deliver "#{@url}/#{path}", data
297
+
298
+ end
299
+
300
+
301
+ def raw_deliver(path, data)
302
+
303
+ payload = data.to_json
304
+
305
+ @delivered = false
306
+ @retries = 0
307
+
308
+ result = {:code => 0, :headers => String.new, :body => String.new}
309
+
310
+ while !@delivered && (@retries < @max_retries)
311
+ @retries += 1
312
+ begin
313
+
314
+ end_point = RestClient::Resource.new path
315
+
316
+ sig = calc @secret_key, payload
317
+
318
+ headers_to_send = {:content_type => :json, :accept => :json}
319
+ headers_to_send["X_HUB_SIGNATURE"] = sig unless @secret_key.empty?
320
+ response = end_point.post payload, headers_to_send
321
+
322
+ puts headers_to_send.inspect
323
+
324
+ if (200..201) === response.code
325
+ @delivered = true
326
+ @log.info "Payload delivered to #{path} #{response.code}"
327
+
328
+ result[:code] = response.code
329
+ result[:headers] = response.headers
330
+ result[:body] = response.body
331
+
332
+ return result
333
+ else
334
+ @log.warn "#{response.code}"
335
+
336
+ @log.warn "Retrying #{@retries}/#{@max_retries} in #{@retry_interval} seconds..."
337
+
338
+ sleep RETRY_INTERVAL
339
+ end
340
+ rescue Exception => e
341
+ @log.fatal "ERROR: #{e}"
342
+
343
+ @log.fatal "Retrying #{@retries}/#{@max_retries} in #{@retry_interval} seconds..."
344
+ end
345
+
346
+ end # while
347
+
348
+ return result
349
+
350
+ end
351
+ end
352
+
353
+ end
@@ -0,0 +1,3 @@
1
+ module BarnyardCcfeeder
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,30 @@
1
+ require "barnyard_ccfeeder"
2
+ require "aws-sdk"
3
+
4
+ describe "this" do
5
+
6
+ it "should load properly" do
7
+
8
+ crop_number = 13
9
+
10
+ cc = BarnyardCcfeeder::CacheCow.new :url => "http://localhost:3000"
11
+
12
+ cc.subscriptions.each do |subscription_id, subscription|
13
+
14
+ unless subscription["active"] == true
15
+ puts("#{self.name} Subscription #{subscription_id} is not active.")
16
+ next
17
+ end
18
+
19
+ if cc.crops[subscription["crop_id"]]["crop_number"] == crop_number
20
+
21
+ puts "subscribed #{subscription["subscriber_id"]} crop #{crop_number}"
22
+
23
+ else
24
+ puts("# #{cc.subscribers[subscription["subscriber_id"]]["name"]} is subscribed to #{cc.crops_by_crop_number[crop_number]["name"]}")
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,17 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ # Run specs in random order to surface order dependencies. If you find an
13
+ # order dependency and want to debug it, you can fix the order by providing
14
+ # the seed, which is printed after each run.
15
+ # --seed 1234
16
+ config.order = 'random'
17
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: barnyard_ccfeeder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jon Gillies
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70156890829980 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70156890829980
25
+ - !ruby/object:Gem::Dependency
26
+ name: aws-sdk
27
+ requirement: &70156890829560 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70156890829560
36
+ - !ruby/object:Gem::Dependency
37
+ name: logger
38
+ requirement: &70156890829140 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70156890829140
47
+ - !ruby/object:Gem::Dependency
48
+ name: rest-client
49
+ requirement: &70156890828720 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *70156890828720
58
+ - !ruby/object:Gem::Dependency
59
+ name: crack
60
+ requirement: &70156890828300 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *70156890828300
69
+ - !ruby/object:Gem::Dependency
70
+ name: json
71
+ requirement: &70156890827880 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *70156890827880
80
+ description: Feeds the Cache Cow
81
+ email:
82
+ - supercoder@gmail.com
83
+ executables: []
84
+ extensions: []
85
+ extra_rdoc_files: []
86
+ files:
87
+ - .gitignore
88
+ - .rvmrc
89
+ - Gemfile
90
+ - LICENSE
91
+ - README.md
92
+ - Rakefile
93
+ - barnyard_ccfeeder.gemspec
94
+ - lib/barnyard_ccfeeder.rb
95
+ - lib/barnyard_ccfeeder/version.rb
96
+ - spec/query_spec.rb
97
+ - spec/spec_helper.rb
98
+ homepage: https://github.com/jongillies/barnyard/tree/master/barnyard_ccfeeder
99
+ licenses: []
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ! '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project: barnyard_ccfeeder
118
+ rubygems_version: 1.8.11
119
+ signing_key:
120
+ specification_version: 3
121
+ summary: REST API to the Cache Cow
122
+ test_files:
123
+ - spec/query_spec.rb
124
+ - spec/spec_helper.rb