promoted-ruby-client 0.1.19 → 0.1.23

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
  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.