bucket_cake 0.2.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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