bucket_cake 0.2.0 → 1.0.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: 9f110ceec832023ab706c978ccc006509d2796ff
4
- data.tar.gz: 13399289c80e169fb230dedbdb15fc7250a491a1
3
+ metadata.gz: e31f6c9d7a53111c74ea5c965aa98c2bfbd10ef3
4
+ data.tar.gz: 152f26894f635dd2c05d1990f79d7da47bacfcb4
5
5
  SHA512:
6
- metadata.gz: ae786997482e3be5e536f3657e3335936a82ffc12bd775db4356f926608ced717ae6eceb7f5751d430dff6c41e0850eed69af91e28ab1eb4288caad5d3af9b0b
7
- data.tar.gz: f0e6a0565fea804e9c3c36a9f367f60ef467eb0a4b6288be24abfadbb6a6dd45ea284fbd2f76dc7ea54188b23b79703749b7b9d3eb6da7a3acc9be1ad39785ba
6
+ metadata.gz: fd917f1e01d53d216d94baf41a5ed173a2e0cb044ead85d8e16982faf1cef6f30bb443343569925601882a7d70b848e1035a0e5637f90420ead85748170cfa0d
7
+ data.tar.gz: f244945c1ff6a96f8a7de5b90c4f9ff6274c22f0f35b1e3c5a3148faa7a88f4aa1c3496e554827a94fe69520f32065033d1c15ca64f4c19a9b9991a623c47fcb
@@ -4,7 +4,9 @@ require 'protobuf'
4
4
  require 'active_support/time'
5
5
 
6
6
  require 'bucket_cake/version'
7
- require 'bucket_cake/stream'
7
+ require 'bucket_cake/source'
8
+ require 'bucket_cake/decoder'
9
+ require 'bucket_cake/base'
8
10
 
9
11
  require 'bucket_cake/proto/common.pb'
10
12
  require 'bucket_cake/proto/advertisers.pb'
@@ -12,10 +14,19 @@ require 'bucket_cake/proto/affiliates.pb'
12
14
  require 'bucket_cake/proto/campaigns.pb'
13
15
  require 'bucket_cake/proto/creatives.pb'
14
16
  require 'bucket_cake/proto/offers.pb'
17
+ require 'bucket_cake/proto/clicks.pb'
18
+ require 'bucket_cake/proto/conversions.pb'
19
+ require 'bucket_cake/proto/conversion_changes.pb'
20
+ require 'bucket_cake/proto/cap_states.pb'
15
21
 
16
22
  require 'bucket_cake/proto_ext/time_with_zone'
17
23
 
18
24
  require 'bucket_cake/entities'
19
25
  require 'bucket_cake/values'
26
+ require 'bucket_cake/facts'
20
27
 
21
28
  Protobuf.ignore_unknown_fields = false
29
+
30
+ module BucketCake
31
+ CACHE_PREFIX = 'bucket-cake-latest'.freeze
32
+ end
@@ -0,0 +1,35 @@
1
+ module BucketCake
2
+ class Base
3
+ def initialize(cache)
4
+ @cache = cache
5
+ check_cache!
6
+ end
7
+
8
+ private
9
+
10
+ attr_reader :cache
11
+
12
+ def check_cache!
13
+ return if cache && cache.respond_to?(:read) && cache.respond_to?(:write)
14
+
15
+ fail 'BucketCake: cache parameter must respond to #read and #write. ' \
16
+ 'Use Rails.cache if you are not sure.'
17
+ end
18
+
19
+ def latest(type, klass, &b)
20
+ get Source::Latest.new(type, cache), klass, &b
21
+ end
22
+
23
+ def range(type, klass, &b)
24
+ get Source::Range.new(type, cache), klass, &b
25
+ end
26
+
27
+ def get(source, klass)
28
+ return unless source.new_data?
29
+
30
+ result = yield Decoder.new(source.zip_files, klass).items
31
+ source.confirm!
32
+ result
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,30 @@
1
+ module BucketCake
2
+ class Decoder
3
+ def initialize(zip_files, klass)
4
+ @zip_files = zip_files
5
+ @klass = klass
6
+ end
7
+
8
+ def items
9
+ Enumerator.new do |y|
10
+ zip_files.each do |zip_data|
11
+ unzip_elements(zip_data) do |element|
12
+ y << klass.decode(element)
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :zip_files, :klass
21
+
22
+ def unzip_elements(zip_data)
23
+ Zip::File.open_buffer(zip_data) do |files|
24
+ files.each do |entry|
25
+ yield entry.get_input_stream.read
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,23 +1,23 @@
1
1
  module BucketCake
2
- class Entities
3
- def advertisers
4
- Stream.new('advertisers', Cakeproto::Advertiser).get
2
+ class Entities < Base
3
+ def advertisers(&b)
4
+ latest 'advertisers', Cakeproto::Advertiser, &b
5
5
  end
6
6
 
7
- def affiliates
8
- Stream.new('affiliates', Cakeproto::Affiliate).get
7
+ def affiliates(&b)
8
+ latest 'affiliates', Cakeproto::Affiliate, &b
9
9
  end
10
10
 
11
- def campaigns
12
- Stream.new('campaigns', Cakeproto::Campaign).get
11
+ def campaigns(&b)
12
+ latest 'campaigns', Cakeproto::Campaign, &b
13
13
  end
14
14
 
15
- def creatives
16
- Stream.new('creatives', Cakeproto::Creative).get
15
+ def creatives(&b)
16
+ latest 'creatives', Cakeproto::Creative, &b
17
17
  end
18
18
 
19
- def offers
20
- Stream.new('offers', Cakeproto::Offer).get
19
+ def offers(&b)
20
+ latest 'offers', Cakeproto::Offer, &b
21
21
  end
22
22
  end
23
23
  end
@@ -0,0 +1,19 @@
1
+ module BucketCake
2
+ class Facts < Base
3
+ def clicks(&b)
4
+ range 'clicks', Cakeproto::Click, &b
5
+ end
6
+
7
+ def conversions(&b)
8
+ range 'conversions', Cakeproto::Conversion, &b
9
+ end
10
+
11
+ def conversion_changes(&b)
12
+ range 'conversion_changes', Cakeproto::ConversionChange, &b
13
+ end
14
+
15
+ def cap_states(&b)
16
+ range 'cap_states', Cakeproto::CapState, &b
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # This file is auto-generated. DO NOT EDIT!
5
+ #
6
+
7
+
8
+ ##
9
+ # Imports
10
+ #
11
+
12
+ module Cakeproto
13
+
14
+ ##
15
+ # Message Classes
16
+ #
17
+ class CapState < ::Protobuf::Message; end
18
+
19
+
20
+ ##
21
+ # Message Fields
22
+ #
23
+ class CapState
24
+ optional ::Cakeproto::IdName, :advertiser, 1
25
+ optional ::Cakeproto::IdName, :offer, 2
26
+ optional ::Cakeproto::IdName, :offer_contract, 3
27
+ optional ::Cakeproto::IdName, :affiliate, 4
28
+ optional :int64, :campaign_id, 5
29
+ optional :string, :entity, 6
30
+ optional ::Cakeproto::IdName, :type, 7
31
+ optional ::Cakeproto::IdName, :interval, 8
32
+ optional :bool, :active, 9
33
+ optional ::Cakeproto::TimeWithZone, :start_date, 10
34
+ optional ::Cakeproto::TimeWithZone, :end_date, 11
35
+ optional :int64, :current, 12
36
+ optional :int64, :limit, 13
37
+ end
38
+
39
+ end
40
+
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # This file is auto-generated. DO NOT EDIT!
5
+ #
6
+
7
+
8
+ ##
9
+ # Imports
10
+ #
11
+
12
+ module Cakeproto
13
+
14
+ ##
15
+ # Message Classes
16
+ #
17
+ class Click < ::Protobuf::Message; end
18
+
19
+
20
+ ##
21
+ # Message Fields
22
+ #
23
+ class Click
24
+ optional :int64, :id, 1
25
+ optional :int64, :visitor_id, 2
26
+ optional :int64, :request_session_id, 3
27
+ optional ::Cakeproto::TimeWithZone, :click_date, 4
28
+ optional ::Cakeproto::IdName, :affiliate, 5
29
+ optional ::Cakeproto::IdName, :advertiser, 6
30
+ optional ::Cakeproto::IdName, :offer, 7
31
+ optional ::Cakeproto::IdName, :offer_contract, 8
32
+ optional :int64, :campaign_id, 9
33
+ optional ::Cakeproto::IdName, :creative, 10
34
+ optional :string, :sub_id1, 11
35
+ optional :string, :sub_id2, 12
36
+ optional :string, :sub_id3, 13
37
+ optional :string, :sub_id4, 14
38
+ optional :string, :sub_id5, 15
39
+ optional :string, :ip_address, 16
40
+ optional :string, :user_agent, 17
41
+ optional :string, :referrer_url, 18
42
+ optional :string, :request_url, 19
43
+ optional :string, :redirect_url, 20
44
+ optional ::Cakeproto::Country, :country, 21
45
+ optional ::Cakeproto::Region, :region, 22
46
+ optional ::Cakeproto::IdName, :isp, 23
47
+ optional :string, :disposition, 24
48
+ optional :int64, :paid_action, 25
49
+ end
50
+
51
+ end
52
+
@@ -14,8 +14,10 @@ module Cakeproto
14
14
  class Currency < ::Protobuf::Message; end
15
15
  class PixelInfo < ::Protobuf::Message; end
16
16
  class Money < ::Protobuf::Message; end
17
+ class MoneyWithCurrency < ::Protobuf::Message; end
17
18
  class MediaType < ::Protobuf::Message; end
18
19
  class Country < ::Protobuf::Message; end
20
+ class Region < ::Protobuf::Message; end
19
21
  class SuppressionList < ::Protobuf::Message; end
20
22
  class Contact < ::Protobuf::Message; end
21
23
  class Blacklist < ::Protobuf::Message; end
@@ -24,6 +26,7 @@ module Cakeproto
24
26
  class EventOverride < ::Protobuf::Message; end
25
27
  class Upsell < ::Protobuf::Message; end
26
28
  class ExchangeRate < ::Protobuf::Message; end
29
+ class Disposition < ::Protobuf::Message; end
27
30
 
28
31
 
29
32
  ##
@@ -59,6 +62,12 @@ module Cakeproto
59
62
  optional :string, :formatted_amount, 3
60
63
  end
61
64
 
65
+ class MoneyWithCurrency
66
+ optional :int64, :currency_id, 1
67
+ optional :double, :amount, 2
68
+ optional :string, :formatted_amount, 3
69
+ end
70
+
62
71
  class MediaType
63
72
  optional :int64, :id, 1
64
73
  optional :string, :name, 2
@@ -71,6 +80,11 @@ module Cakeproto
71
80
  optional :string, :name, 2
72
81
  end
73
82
 
83
+ class Region
84
+ optional :string, :code, 1
85
+ optional :string, :name, 2
86
+ end
87
+
74
88
  class SuppressionList
75
89
  optional :int64, :id, 1
76
90
  optional :string, :name, 2
@@ -150,5 +164,13 @@ module Cakeproto
150
164
  optional :double, :rate, 5
151
165
  end
152
166
 
167
+ class Disposition
168
+ optional :int64, :id, 1
169
+ optional :string, :name, 2
170
+ optional ::Cakeproto::IdName, :type, 3
171
+ optional :string, :contact, 4
172
+ optional ::Cakeproto::TimeWithZone, :disposition_date, 5
173
+ end
174
+
153
175
  end
154
176
 
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # This file is auto-generated. DO NOT EDIT!
5
+ #
6
+
7
+
8
+ ##
9
+ # Imports
10
+ #
11
+
12
+ module Cakeproto
13
+
14
+ ##
15
+ # Message Classes
16
+ #
17
+ class ConversionChange < ::Protobuf::Message; end
18
+
19
+
20
+ ##
21
+ # Message Fields
22
+ #
23
+ class ConversionChange
24
+ optional :int64, :id, 1
25
+ optional ::Cakeproto::TimeWithZone, :conversion_date, 2
26
+ optional ::Cakeproto::TimeWithZone, :last_updated, 3
27
+ optional ::Cakeproto::MoneyWithCurrency, :paid, 4
28
+ optional ::Cakeproto::MoneyWithCurrency, :received, 5
29
+ optional ::Cakeproto::Disposition, :current_disposition, 6
30
+ optional :string, :note, 7
31
+ end
32
+
33
+ end
34
+
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+
3
+ ##
4
+ # This file is auto-generated. DO NOT EDIT!
5
+ #
6
+
7
+
8
+ ##
9
+ # Imports
10
+ #
11
+
12
+ module Cakeproto
13
+
14
+ ##
15
+ # Message Classes
16
+ #
17
+ class Conversion < ::Protobuf::Message; end
18
+
19
+
20
+ ##
21
+ # Message Fields
22
+ #
23
+ class Conversion
24
+ optional :int64, :id, 1
25
+ optional :int64, :visitor_id, 2
26
+ optional :int64, :request_session_id, 3
27
+ optional :int64, :click_id, 4
28
+ optional :int64, :click_request_session_id, 5
29
+ optional ::Cakeproto::TimeWithZone, :conversion_date, 6
30
+ optional ::Cakeproto::TimeWithZone, :click_date, 7
31
+ optional ::Cakeproto::TimeWithZone, :last_updated, 8
32
+ optional ::Cakeproto::IdName, :event, 9
33
+ optional ::Cakeproto::IdName, :affiliate, 10
34
+ optional ::Cakeproto::IdName, :advertiser, 11
35
+ optional ::Cakeproto::IdName, :offer, 12
36
+ optional ::Cakeproto::IdName, :offer_contract, 13
37
+ optional :int64, :campaign_id, 14
38
+ optional ::Cakeproto::IdName, :campaign_type, 15
39
+ optional ::Cakeproto::IdName, :creative, 16
40
+ optional :string, :sub_id1, 17
41
+ optional :string, :sub_id2, 18
42
+ optional :string, :sub_id3, 19
43
+ optional :string, :sub_id4, 20
44
+ optional :string, :sub_id5, 21
45
+ optional :string, :ip_address, 22
46
+ optional :string, :click_ip_address, 36
47
+ optional :string, :user_agent, 23
48
+ optional :string, :click_user_agent, 37
49
+ optional :string, :source_type, 24
50
+ optional ::Cakeproto::IdName, :price_format, 25
51
+ optional ::Cakeproto::MoneyWithCurrency, :paid, 26
52
+ optional ::Cakeproto::MoneyWithCurrency, :received, 27
53
+ optional :int64, :step_reached, 28
54
+ optional :string, :transaction_id, 29
55
+ optional ::Cakeproto::Disposition, :current_disposition, 30
56
+ optional ::Cakeproto::MoneyWithCurrency, :order_total, 38
57
+ optional ::Cakeproto::Country, :country, 31
58
+ optional ::Cakeproto::Region, :region, 32
59
+ optional ::Cakeproto::IdName, :language, 33
60
+ optional ::Cakeproto::IdName, :isp, 34
61
+ optional :string, :note, 35
62
+ end
63
+
64
+ end
65
+
@@ -0,0 +1,83 @@
1
+ module BucketCake
2
+ class Source
3
+ def initialize(type, cache)
4
+ @type = type
5
+ @cache = cache
6
+ end
7
+
8
+ def zip_files
9
+ Enumerator.new do |y|
10
+ objects.each do |object|
11
+ next unless check_success(object.key)
12
+ next unless object.key =~ %r{/part\d{3}\.zip\z}
13
+
14
+ io = object.get.body
15
+
16
+ # we need to force binary encoding, otherwise binary zip data will be parsed as utf-8
17
+ io.set_encoding('BINARY'.freeze)
18
+
19
+ y << io.read
20
+ end
21
+ end
22
+ end
23
+
24
+ def check_success(key)
25
+ @success_files ||= Set.new
26
+ @success_files << key if key.end_with?('/SUCCESS'.freeze)
27
+
28
+ # This relies on the fact that SUCCESS files always come before partNNN.zip files.
29
+ # But that is fine because S3 guarantees alphabetical order.
30
+ @success_files.include?(File.dirname(key) + '/SUCCESS'.freeze)
31
+ end
32
+
33
+ def new_data?
34
+ current_latest_path != cache_latest_path
35
+ end
36
+
37
+ def confirm!
38
+ cache.write(cache_key, current_latest_path)
39
+ end
40
+
41
+ private
42
+
43
+ attr_reader :type, :cache
44
+
45
+ def cache_key
46
+ "#{CACHE_PREFIX}-#{type}"
47
+ end
48
+
49
+ def current_latest_path
50
+ @current_latest_path ||= bucket.object("#{type}/latest").get.body.read
51
+ end
52
+
53
+ def cache_latest_path
54
+ @cache_latest_path ||= cache.read(cache_key)
55
+ end
56
+
57
+ def bucket
58
+ @bucket ||= Aws::S3::Bucket.new(ENV.fetch('CAKE_DATA_BUCKET'.freeze))
59
+ end
60
+ end
61
+
62
+ class Source::Latest < Source
63
+ private
64
+
65
+ def objects
66
+ bucket.objects(prefix: "#{type}/#{current_latest_path}/")
67
+ end
68
+ end
69
+
70
+ class Source::Range < Source
71
+ private
72
+
73
+ def objects
74
+ # If we don't have a timestamp in cache, return everything
75
+ return bucket.objects(prefix: "#{type}/") if cache_latest_path.nil?
76
+
77
+ # This returns all objects after the current timestamp.
78
+ # By using the 'xxx' suffix, none of the objects of the given timestamp are returned.
79
+ # S3 ensures alphabetical order of the results, so this works fine for date ranges.
80
+ bucket.objects(marker: "#{type}/#{cache_latest_path}/xxx", prefix: "#{type}/")
81
+ end
82
+ end
83
+ end
@@ -1,35 +1,35 @@
1
1
  module BucketCake
2
- class Values
3
- def affiliate_tiers
4
- Stream.new('affiliate_tiers', Cakeproto::IdName).get
2
+ class Values < Base
3
+ def affiliate_tiers(&b)
4
+ latest 'affiliate_tiers', Cakeproto::IdName, &b
5
5
  end
6
6
 
7
- def blacklist_reasons
8
- Stream.new('blacklist_reasons', Cakeproto::IdName).get
7
+ def blacklist_reasons(&b)
8
+ latest 'blacklist_reasons', Cakeproto::IdName, &b
9
9
  end
10
10
 
11
- def countries
12
- Stream.new('countries', Cakeproto::Country).get
11
+ def countries(&b)
12
+ latest 'countries', Cakeproto::Country, &b
13
13
  end
14
14
 
15
- def currencies
16
- Stream.new('currencies', Cakeproto::Currency).get
15
+ def currencies(&b)
16
+ latest 'currencies', Cakeproto::Currency, &b
17
17
  end
18
18
 
19
- def exchange_rates
20
- Stream.new('exchange_rates', Cakeproto::ExchangeRate).get
19
+ def exchange_rates(&b)
20
+ latest 'exchange_rates', Cakeproto::ExchangeRate, &b
21
21
  end
22
22
 
23
- def media_types
24
- Stream.new('media_types', Cakeproto::IdName).get
23
+ def media_types(&b)
24
+ latest 'media_types', Cakeproto::IdName, &b
25
25
  end
26
26
 
27
- def payment_types
28
- Stream.new('payment_types', Cakeproto::IdName).get
27
+ def payment_types(&b)
28
+ latest 'payment_types', Cakeproto::IdName, &b
29
29
  end
30
30
 
31
- def verticals
32
- Stream.new('verticals', Cakeproto::IdName).get
31
+ def verticals(&b)
32
+ latest 'verticals', Cakeproto::IdName, &b
33
33
  end
34
34
  end
35
35
  end
@@ -1,3 +1,3 @@
1
1
  module BucketCake
2
- VERSION = '0.2.0'.freeze
2
+ VERSION = '1.0.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bucket_cake
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ad2games developers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-02 00:00:00.000000000 Z
11
+ date: 2015-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -172,15 +172,22 @@ extensions: []
172
172
  extra_rdoc_files: []
173
173
  files:
174
174
  - lib/bucket_cake.rb
175
+ - lib/bucket_cake/base.rb
176
+ - lib/bucket_cake/decoder.rb
175
177
  - lib/bucket_cake/entities.rb
178
+ - lib/bucket_cake/facts.rb
176
179
  - lib/bucket_cake/proto/advertisers.pb.rb
177
180
  - lib/bucket_cake/proto/affiliates.pb.rb
178
181
  - lib/bucket_cake/proto/campaigns.pb.rb
182
+ - lib/bucket_cake/proto/cap_states.pb.rb
183
+ - lib/bucket_cake/proto/clicks.pb.rb
179
184
  - lib/bucket_cake/proto/common.pb.rb
185
+ - lib/bucket_cake/proto/conversion_changes.pb.rb
186
+ - lib/bucket_cake/proto/conversions.pb.rb
180
187
  - lib/bucket_cake/proto/creatives.pb.rb
181
188
  - lib/bucket_cake/proto/offers.pb.rb
182
189
  - lib/bucket_cake/proto_ext/time_with_zone.rb
183
- - lib/bucket_cake/stream.rb
190
+ - lib/bucket_cake/source.rb
184
191
  - lib/bucket_cake/values.rb
185
192
  - lib/bucket_cake/version.rb
186
193
  homepage: https://github.com/ad2games/bucket_cake
@@ -203,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
203
210
  version: '0'
204
211
  requirements: []
205
212
  rubyforge_project:
206
- rubygems_version: 2.5.0
213
+ rubygems_version: 2.5.1
207
214
  signing_key:
208
215
  specification_version: 4
209
216
  summary: Get cakeproto objects from S3.
@@ -1,45 +0,0 @@
1
- module BucketCake
2
- class Stream
3
- def initialize(type, klass)
4
- @type = type
5
- @klass = klass
6
- end
7
-
8
- def get
9
- Enumerator.new do |y|
10
- objects.each do |object|
11
- unzip_elements(object.get.body) do |element|
12
- y << klass.decode(element)
13
- end
14
- end
15
- end
16
- end
17
-
18
- private
19
-
20
- attr_reader :type, :klass
21
-
22
- def unzip_elements(zip_io)
23
- # we need to force binary encoding, otherwise binary zip data will be parsed as utf-8
24
- zip_io.set_encoding('BINARY'.freeze)
25
-
26
- Zip::File.open_buffer(zip_io.read) do |files|
27
- files.each do |entry|
28
- yield entry.get_input_stream.read
29
- end
30
- end
31
- end
32
-
33
- def objects
34
- bucket.objects(prefix: "#{type}/#{latest_path}/part")
35
- end
36
-
37
- def latest_path
38
- bucket.object("#{type}/latest").get.body.read
39
- end
40
-
41
- def bucket
42
- @bucket ||= Aws::S3::Bucket.new(ENV.fetch('CAKE_DATA_BUCKET'.freeze))
43
- end
44
- end
45
- end