promoted-ruby-client 0.1.19 → 0.1.23

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
  SHA256:
3
- metadata.gz: 6b8a39c8af4d21ae9987db29f0041e57d54de87da119b799e89091069a0bfbc2
4
- data.tar.gz: 7b3932706882a896f330b0bd0a3d05671111e80b97fac4403e355ae30e537750
3
+ metadata.gz: 280c1b17bece86732743246173338746e1ab9d414b9515bc9fc77c8c598ae319
4
+ data.tar.gz: 1fed11fd16de69732e6f61d1d1e33b31c812151413a34d881b8dd7aace712daa
5
5
  SHA512:
6
- metadata.gz: 3146dc2f31afa84fa2b332b1cdb5ca145e7aa51140ae14503a8ca8a4aebc96bb59c4313ee10884b85ba819c930f40f9dd88e7d88454a39a9748b42f3e7d827e5
7
- data.tar.gz: 903cb0dca7f83acfa605db3be223833ffebe78d0e530b1e98599ed2b8b15e2b5babffb1e40704789bab45f42f3d8372a46e2263733428da2e9fea90860003cb0
6
+ metadata.gz: 997ca8c047a62a08b2f5e008184719c3e3f1f1dac45cfbccf41c4f451b8fad3f9a8aab7737e148a6281b4a9600e8c2ff6b8bfe9a269aba417ab7bf21f735fcd3
7
+ data.tar.gz: 274d3ce469128a6fa7da5fc127b65e9a3e1cc2327b322af5719182f06a37ada713806458c754d2efed6d6a21ad7ab945890541d5e3d1247844b66fa6b3a77a16
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- promoted-ruby-client (0.1.19)
4
+ promoted-ruby-client (0.1.23)
5
5
  concurrent-ruby (~> 1)
6
6
  faraday (>= 0.9.0)
7
7
  faraday_middleware (>= 0.9.0)
data/README.md CHANGED
@@ -49,6 +49,7 @@ Name | Type | Description
49
49
  ```:perform_checks``` | Boolean | Whether or not to perform detailed input validation, defaults to true but may be disabled for performance
50
50
  ```:logger``` | Ruby Logger-compatible logger | Defaults to nil (no logging). Example: ```Logger.new(STDERR, :progname => 'promotedai')```
51
51
  ```:shadow_traffic_delivery_percent``` | Number between 0 and 1 | % of ```prepare_for_logging``` traffic that gets directed to Delivery API as "shadow traffic". Defaults to 0 (no shadow traffic).
52
+ ```:send_shadow_traffic_for_control``` | Boolean | If true, the ```deliver``` method will send shadow traffic for users in the CONTROL arm of an experiment. Defaults to true.
52
53
  ```:default_request_headers``` | Hash | Additional headers to send on the request beyond ```x-api-key```. Defaults to {}
53
54
  ```:default_only_log``` | Boolean | If true, the ```deliver``` method will not direct traffic to Delivery API but rather return a request suitable for logging. Defaults to false.
54
55
  ```:should_apply_treatment_func``` | Proc | Called during delivery, accepts an experiment and returns a Boolean indicating whether the request should be considered part of the control group (false) or in the experiment (true). If nil, the default behavior of checking the experiement ```:arm``` is applied.
@@ -62,6 +63,7 @@ Field Name | Type | Optional? | Description
62
63
  ---------- | ---- | --------- | -----------
63
64
  ```:user_id``` | String | Yes | The platform user id, cleared from Promoted logs.
64
65
  ```:log_user_id``` | String | Yes | A different user id (presumably a UUID) disconnected from the platform user id, good for working with unauthenticated users or implementing right-to-be-forgotten.
66
+ ```:is_internal_user``` | Boolean | Yes | If this user is a test user or not, defaults to false.
65
67
 
66
68
  ---
67
69
  ### CohortMembership
@@ -93,6 +95,8 @@ Field Name | Type | Optional? | Description
93
95
  ```:insertion_id``` | String | Yes | Generated by the SDK (*do not set*)
94
96
  ```:request_id``` | String | Yes | Generated by the SDK when needed (*do not set*)
95
97
  ```:content_id``` | String | No | Identifier for the content to be shown, must be set.
98
+ ```:retrieval_rank``` | Number | Yes | Optional original ranking of this content item.
99
+ ```:retrieval_score``` | Number | Yes | Optional original quality score of this content item.
96
100
  ```:properties``` | Properties | Yes | Any additional custom properties to associate. For v1 integrations, it is fine not to fill in all the properties.
97
101
  ---
98
102
  ### Size
@@ -103,6 +107,14 @@ Field Name | Type | Optional? | Description
103
107
  ```:height``` | Integer | No | Screen height
104
108
  ---
105
109
 
110
+ ### Screen
111
+ State of the screen including scaling.
112
+ Field Name | Type | Optional? | Description
113
+ ---------- | ---- | --------- | -----------
114
+ ```:size``` | Size | Yes | Screen size
115
+ ```:scale``` | Float | Yes | Current screen scaling factor
116
+ ---
117
+
106
118
  ### ClientHints
107
119
  Alternative to user-agent strings. See https://raw.githubusercontent.com/snowplow/iglu-central/master/schemas/org.ietf/http_client_hints/jsonschema/1-0-0
108
120
  Field Name | Type | Optional? | Description
@@ -131,7 +143,6 @@ Field Name | Type | Optional? | Description
131
143
  ```:latitude``` | Float | No | Location latitude
132
144
  ```:longitude``` | Float | No | Location longitude
133
145
  ```:accuracy_in_meters``` | Integer | Yes | Location accuracy if available
134
- ```:client_hints``` | ClientHints | Yes | HTTP client hints structure
135
146
  ---
136
147
 
137
148
  ### Browser
@@ -140,7 +151,7 @@ Field Name | Type | Optional? | Description
140
151
  ---------- | ---- | --------- | -----------
141
152
  ```:user_agent``` | String | Yes | Browser user agent string
142
153
  ```:viewport_size``` | Size | Yes | Size of the browser viewport
143
- ```:
154
+ ```:client_hints``` | ClientHints | Yes | HTTP client hints structure
144
155
  ---
145
156
  ### Device
146
157
  Information about the user's device.
data/dev.md CHANGED
@@ -4,5 +4,5 @@
4
4
  2. Get credentials for deployment from 1password.
5
5
  3. Modify `promoted-ruby-client.gemspec`'s push block.
6
6
  4. Run `gem build promoted-ruby-client.gemspec` to generate `gem`.
7
- 5. Run (using new output) `gem push promoted-ruby-client-0.1.19.gem`
7
+ 5. Run (using new output) `gem push promoted-ruby-client-0.1.23.gem`
8
8
  6. Update README with new version.
@@ -11,13 +11,13 @@ module Promoted
11
11
  end
12
12
 
13
13
  class Pager
14
- def validate_paging (insertions, paging)
14
+ def validate_paging(insertions, paging)
15
15
  if paging && paging[:offset] && paging[:offset] >= insertions.length
16
16
  raise InvalidPagingError.new("Invalid page offset (insertion size #{insertions.length}, offset #{paging[:offset]})", [])
17
17
  end
18
18
  end
19
19
 
20
- def apply_paging (insertions, insertion_page_type, paging = nil)
20
+ def apply_paging(insertions, insertion_page_type, paging = nil)
21
21
  begin
22
22
  validate_paging(insertions, paging)
23
23
  rescue InvalidPagingError => err
@@ -47,7 +47,7 @@ module Promoted
47
47
  size = insertions.length
48
48
  end
49
49
 
50
- final_insertion_size = [size, insertions.length].min
50
+ final_insertion_size = [size, insertions.length - index].min
51
51
  insertion_page = Array.new(final_insertion_size)
52
52
  0.upto(final_insertion_size - 1) {|i|
53
53
  insertion = insertions[index]
@@ -63,5 +63,5 @@ module Promoted
63
63
  end
64
64
  end
65
65
  end
66
- end
66
+ end
67
67
  end
@@ -57,7 +57,7 @@ module Promoted
57
57
  params = {
58
58
  user_info: user_info,
59
59
  timing: timing,
60
- client_info: @client_info.merge({ :client_type => Promoted::Ruby::Client::CLIENT_TYPE['PLATFORM_SERVER'] }),
60
+ client_info: merge_client_info_defaults,
61
61
  device: @device,
62
62
  platform_id: @platform_id,
63
63
  view_id: @view_id,
@@ -78,7 +78,7 @@ module Promoted
78
78
  # to the responses.
79
79
  def fill_details_from_response response_insertions
80
80
  if !response_insertions then
81
- response_insertions = full_insertion
81
+ response_insertions = []
82
82
  end
83
83
 
84
84
  props = @full_insertion.each_with_object({}) do |insertion, hash|
@@ -104,8 +104,13 @@ module Promoted
104
104
  params = {
105
105
  user_info: user_info,
106
106
  timing: timing,
107
- client_info: @client_info,
108
- device: @device
107
+ client_info: merge_client_info_defaults,
108
+ device: @device,
109
+ delivery_log: [{
110
+ execution: {
111
+ execution_server: Promoted::Ruby::Client::EXECUTION_SERVER['SDK']
112
+ }
113
+ }]
109
114
  }
110
115
 
111
116
  if @experiment
@@ -115,12 +120,16 @@ module Promoted
115
120
  # Log request allows for multiple requests but here we only send one.
116
121
  if include_request
117
122
  request[:request_id] = request[:request_id] || @id_generator.newID
118
- params[:request] = [request]
123
+ # Set request on delivery log.
124
+ params[:delivery_log][0][:request] = request
119
125
  end
120
126
 
121
127
  if include_insertions
122
- params[:insertion] = compact_metrics_properties if include_insertions
123
- add_missing_ids_on_insertions! request, params[:insertion]
128
+ # Add a response containing compacted insertions to delivery log.
129
+ params[:delivery_log][0][:response] = {
130
+ insertion: compact_metrics_properties
131
+ }
132
+ add_missing_ids_on_insertions! request, params[:delivery_log][0][:response][:insertion]
124
133
  end
125
134
 
126
135
  params.clean!
@@ -178,7 +187,6 @@ module Promoted
178
187
  insertion_obj = Hash[insertion_obj]
179
188
  insertion_obj[:user_info] = user_info
180
189
  insertion_obj[:timing] = timing
181
- insertion_obj[:insertion_id] = @id_generator.newID
182
190
  insertion_obj[:request_id] = request_id
183
191
  insertion_obj[:position] = offset + index
184
192
  insertion_obj = compact_one_insertion(insertion_obj, @to_compact_metrics_properties_func)
@@ -187,18 +195,31 @@ module Promoted
187
195
  @insertion
188
196
  end
189
197
 
198
+ def add_missing_insertion_ids! insertions
199
+ insertions.each do |insertion|
200
+ insertion[:insertion_id] = @id_generator.newID if not insertion[:insertion_id]
201
+ end
202
+ end
203
+
190
204
  def client_request_id
191
205
  request[:client_request_id]
192
206
  end
193
207
 
194
208
  private
195
209
 
210
+ def merge_client_info_defaults
211
+ return @client_info.merge({
212
+ :client_type => Promoted::Ruby::Client::CLIENT_TYPE['PLATFORM_SERVER'],
213
+ :traffic_type => Promoted::Ruby::Client::TRAFFIC_TYPE['PRODUCTION']
214
+ })
215
+ end
216
+
196
217
  def add_missing_ids_on_insertions! request, insertions
197
218
  insertions.each do |insertion|
198
- insertion[:insertion_id] = @id_generator.newID if not insertion[:insertion_id]
199
219
  insertion[:session_id] = request[:session_id] if request[:session_id]
200
220
  insertion[:request_id] = request[:request_id] if request[:request_id]
201
221
  end
222
+ add_missing_insertion_ids! insertions
202
223
  end
203
224
 
204
225
  # A list of the response Insertions. This client expects lists to be truncated
@@ -14,6 +14,10 @@ module Promoted
14
14
  {
15
15
  :name => :log_user_id,
16
16
  :type => String
17
+ },
18
+ {
19
+ :name => :is_internal_user,
20
+ :type => [TrueClass, FalseClass]
17
21
  }
18
22
  ]
19
23
  )
@@ -55,6 +59,14 @@ module Promoted
55
59
  {
56
60
  :name => :delivery_score,
57
61
  :type => Integer
62
+ },
63
+ {
64
+ :name => :retrieval_rank,
65
+ :type => Integer
66
+ },
67
+ {
68
+ :name => :retrieval_score,
69
+ :type => Float
58
70
  }
59
71
  ]
60
72
  )
@@ -133,7 +145,6 @@ module Promoted
133
145
  req[:full_insertion].each do |insertion_hash|
134
146
  raise ValidationError.new("Insertion.requestId should not be set") if insertion_hash[:request_id]
135
147
  raise ValidationError.new("'Insertion.insertionId should not be set") if insertion_hash[:insertion_id]
136
- raise ValidationError.new("Insertion.deliveryScore should not be set") if insertion_hash[:delivery_score]
137
148
  end
138
149
  end
139
150
 
@@ -147,7 +158,11 @@ module Promoted
147
158
 
148
159
  # If a field is provided as non-nil, it should be of the correct type.
149
160
  if field[:type] && obj.has_key?(field[:name]) && obj[field[:name]] != nil then
150
- raise ValidationError.new(field[:name].to_s + " should be a " + field[:type].to_s) if !obj[field[:name]].is_a?(field[:type])
161
+ if field[:type].is_a?(Array) then
162
+ raise ValidationError.new(field[:name].to_s + " should be one of " + field[:type].to_s) if !field[:type].include?(obj[field[:name]].class)
163
+ else
164
+ raise ValidationError.new(field[:name].to_s + " should be a " + field[:type].to_s) if !obj[field[:name]].is_a?(field[:type])
165
+ end
151
166
  end
152
167
  }
153
168
  end
@@ -1,7 +1,7 @@
1
1
  module Promoted
2
2
  module Ruby
3
3
  module Client
4
- VERSION = "0.1.19"
4
+ VERSION = "0.1.23"
5
5
  end
6
6
  end
7
7
  end
@@ -19,7 +19,8 @@ module Promoted
19
19
  class Error < StandardError; end
20
20
 
21
21
  attr_reader :perform_checks, :default_only_log, :delivery_timeout_millis, :metrics_timeout_millis, :should_apply_treatment_func,
22
- :default_request_headers, :http_client, :logger, :shadow_traffic_delivery_percent, :async_shadow_traffic
22
+ :default_request_headers, :http_client, :logger, :shadow_traffic_delivery_percent, :async_shadow_traffic,
23
+ :send_shadow_traffic_for_control
23
24
 
24
25
  attr_accessor :request_logging_on, :enabled
25
26
 
@@ -39,7 +40,7 @@ module Promoted
39
40
 
40
41
  ##
41
42
  # Create and configure a new Promoted client.
42
- def initialize (params={})
43
+ def initialize(params={})
43
44
  @perform_checks = true
44
45
  if params[:perform_checks] != nil
45
46
  @perform_checks = params[:perform_checks]
@@ -79,6 +80,11 @@ module Promoted
79
80
  @async_shadow_traffic = params[:async_shadow_traffic] || false
80
81
  end
81
82
 
83
+ @send_shadow_traffic_for_control = true
84
+ if params[:send_shadow_traffic_for_control] != nil
85
+ @send_shadow_traffic_for_control = params[:send_shadow_traffic_for_control] || false
86
+ end
87
+
82
88
  @pool = nil
83
89
  if @async_shadow_traffic
84
90
  # Thread pool to process delivery of shadow traffic. Will silently drop excess requests beyond the queue
@@ -161,9 +167,8 @@ module Promoted
161
167
  cohort_membership_to_log = delivery_request_builder.new_cohort_membership_to_log
162
168
 
163
169
  if should_apply_treatment(cohort_membership_to_log)
164
- delivery_request_params = delivery_request_builder.delivery_request_params
165
-
166
- # Call Delivery API
170
+ # Call Delivery API to get insertions to use
171
+ delivery_request_params = delivery_request_builder.delivery_request_params
167
172
  begin
168
173
  response = send_request(delivery_request_params, @delivery_endpoint, @delivery_timeout_millis, @delivery_api_key, headers)
169
174
  rescue StandardError => err
@@ -172,17 +177,20 @@ module Promoted
172
177
  deliver_err = true
173
178
  @logger.error("Error calling delivery: " + err.message) if @logger
174
179
  end
175
-
176
- insertions_from_delivery = (response != nil && !deliver_err);
177
- response_insertions = delivery_request_builder.fill_details_from_response(
178
- response ? response[:insertion] : [])
180
+ elsif @send_shadow_traffic_for_control
181
+ # Call Delivery API to send shadow traffic. This will create the request params with traffic type set.
182
+ deliver_shadow_traffic args, headers
179
183
  end
184
+
185
+ insertions_from_delivery = (response != nil && !deliver_err);
186
+ response_insertions = delivery_request_builder.fill_details_from_response(
187
+ response && response[:insertion] || [])
180
188
  end
181
189
 
182
190
  request_to_log = nil
183
191
  if !insertions_from_delivery then
184
192
  request_to_log = delivery_request_builder.request
185
- response_insertions = @pager.apply_paging(delivery_request_builder.full_insertion, Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'], delivery_request_builder.request[:paging])
193
+ response_insertions = build_sdk_response_insertions(delivery_request_builder)
186
194
  end
187
195
 
188
196
  log_req = nil
@@ -266,6 +274,14 @@ module Promoted
266
274
 
267
275
  private
268
276
 
277
+ ##
278
+ # Creates response insertions for SDK-side delivery, when we don't get response insertions from Delivery API.
279
+ def build_sdk_response_insertions delivery_request_builder
280
+ response_insertions = @pager.apply_paging(delivery_request_builder.full_insertion, Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'], delivery_request_builder.request[:paging])
281
+ delivery_request_builder.add_missing_insertion_ids! response_insertions
282
+ return response_insertions
283
+ end
284
+
269
285
  def do_warmup
270
286
  if !@delivery_endpoint
271
287
  # Warmup only supported when delivery is enabled.
@@ -318,7 +334,7 @@ module Promoted
318
334
 
319
335
  ellapsed_time = Time.now - start_time
320
336
  @logger.debug("Sync send_request completed in #{ellapsed_time.to_f * 1000} ms") if @logger
321
- end
337
+ end
322
338
 
323
339
  return resp
324
340
  end
@@ -357,7 +373,7 @@ module Promoted
357
373
 
358
374
  if !@async_shadow_traffic
359
375
  ellapsed_time = Time.now - start_time
360
- insertions = response ? response[:insertion] : []
376
+ insertions = response && response[:insertion] || []
361
377
  @logger.info("Shadow traffic call completed in #{ellapsed_time.to_f * 1000} ms with #{insertions.length} insertions") if @logger
362
378
  end
363
379
  end
@@ -14,6 +14,7 @@ Gem::Specification.new do |spec|
14
14
  spec.homepage = 'https://github.com/promotedai/promoted-ruby-client'
15
15
  spec.license = 'MIT'
16
16
 
17
+ spec.metadata["allowed_push_host"] = "https://rubygems.org/"
17
18
  spec.metadata["homepage_uri"] = spec.homepage
18
19
  spec.metadata["source_code_uri"] = "https://github.com/promotedai/promoted-ruby-client"
19
20
  spec.metadata["changelog_uri"] = "https://github.com/promotedai/promoted-ruby-client/blob/master/CHANGELOG.md"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: promoted-ruby-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.19
4
+ version: 0.1.23
5
5
  platform: ruby
6
6
  authors:
7
7
  - scottmcmaster
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-08-11 00:00:00.000000000 Z
11
+ date: 2021-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -150,6 +150,7 @@ homepage: https://github.com/promotedai/promoted-ruby-client
150
150
  licenses:
151
151
  - MIT
152
152
  metadata:
153
+ allowed_push_host: https://rubygems.org/
153
154
  homepage_uri: https://github.com/promotedai/promoted-ruby-client
154
155
  source_code_uri: https://github.com/promotedai/promoted-ruby-client
155
156
  changelog_uri: https://github.com/promotedai/promoted-ruby-client/blob/master/CHANGELOG.md
@@ -168,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
169
  - !ruby/object:Gem::Version
169
170
  version: '0'
170
171
  requirements: []
171
- rubygems_version: 3.2.24
172
+ rubygems_version: 3.0.3
172
173
  signing_key:
173
174
  specification_version: 4
174
175
  summary: A Ruby Client to contact Promoted APIs.