promoted-ruby-client 1.0.0 → 2.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
  SHA256:
3
- metadata.gz: a3f9ec2c51749dd3819e71b93784a0eea77f4f11b0117ad21c44ae976a2b1d96
4
- data.tar.gz: a507c5f00b3e3cfc8116c67f2413f51e6a9b45827f991ad44953c36b5c44b453
3
+ metadata.gz: e743a5f01479b23e4e68d12262e93549d58a11540c0cf448fe4316c277422373
4
+ data.tar.gz: 65b9c38eab75a844783f3595c05bd1ea6f1f668596f46be2ecd3e370b61a551f
5
5
  SHA512:
6
- metadata.gz: 580f2c7e11d8cc30e1c2d23f2c0b57f311597af695d0179a4d32149d1e4e3723d122e8f2783ce4e1e9b0d09374779a029091106c10612920b7d0c5e942b35ebe
7
- data.tar.gz: 3a75185fe166e28b551eb82fd7cbcb51cf92c1fb8fdf7a1266bbb46715fd8d190ef9df75da5ab438991dde5352c4802abd8d3ee68abf27400aa58ca40037cb8e
6
+ metadata.gz: 68c1e692e7e5af9a3deb344fde3cbc0049e8aa6f775d524bc0a6196646e9736cbfdb269fedf4ae83a07ad24cdab94c7140e555709bf046d72530e2f151c252e1
7
+ data.tar.gz: d0ef6502f473fb279a5a1379234c88f1263d7448d66e7d56cc65794d9d6692826f86e8d4934a69f80aececdf8752c993c96044f9b4146bc02d8721ae2d9dc626
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- promoted-ruby-client (1.0.0)
4
+ promoted-ruby-client (2.0.0)
5
5
  concurrent-ruby (~> 1)
6
6
  faraday (>= 0.9.0)
7
7
  faraday_middleware (>= 0.9.0)
data/README.md CHANGED
@@ -205,7 +205,7 @@ Field Name | Type | Optional? | Description
205
205
  Output of ```deliver```, includes the insertions as well as a suitable ```LogRequest``` for forwarding to Metrics API.
206
206
  Field Name | Type | Optional? | Description
207
207
  ---------- | ---- | --------- | -----------
208
- ```:insertion``` | [] of Insertion | No | The insertions, which are from Delivery API (when ```deliver``` was called, i.e. we weren't either only-log or part of an experiment) or the input insertions (when the other conditions don't hold).
208
+ ```:insertion``` | [] of Insertion | No | The paged insertions, which are from Delivery API (when ```deliver``` was called, i.e. we weren't either only-log or part of an experiment) or the input insertions (when the other conditions don't hold).
209
209
  ```:log_request``` | LogRequest | Yes | A message suitable for logging to Metrics API via ```send_log_request```. If the call to ```deliver``` was made (i.e. the request was not part of the CONTROL arm of an experiment or marked to only log), ```:log_request``` will not be set, as you can assume logging was performed on the server-side by Promoted.
210
210
  ```:client_request_id``` | String | Yes | Client-generated request id sent to Delivery API and may be useful for logging and debugging.
211
211
  ```:execution_server``` | one of 'API' or 'SDK' | Yes | Indicates if response insertions on a delivery request came from the API or the SDK.
data/dev.md CHANGED
@@ -1,8 +1,14 @@
1
+ # Run tests
2
+
3
+ ```
4
+ bundle exec rspec
5
+ ```
6
+
1
7
  # Deploy
2
8
 
3
9
  1. Update version number.
4
10
  2. Get credentials for deployment from 1password.
5
11
  3. Modify `promoted-ruby-client.gemspec`'s push block.
6
12
  4. Run `gem build promoted-ruby-client.gemspec` to generate `gem`.
7
- 5. Run (using new output) `gem push promoted-ruby-client-1.0.0.gem`
13
+ 5. Run (using new output) `gem push promoted-ruby-client-2.0.0.gem`
8
14
  6. Update README with new version.
@@ -0,0 +1,61 @@
1
+ module Promoted
2
+ module Ruby
3
+ module Client
4
+ class LogRequestBuilder
5
+ attr_reader :request, :response_insertions, :experiment
6
+ attr_accessor :request, :response_insertions, :experiment
7
+
8
+ def initialize args = {}
9
+ if args[:id_generator]
10
+ @id_generator = args[:id_generator]
11
+ else
12
+ @id_generator = IdGenerator.new
13
+ end
14
+ end
15
+
16
+ def log_request(include_delivery_log:, exec_server:)
17
+ log_req = {
18
+ platform_id: @request[:platform_id],
19
+ user_info: @request[:user_info],
20
+ # For now, we'll just use the request timestamp.
21
+ timing: @request[:timing],
22
+ client_info: @request[:client_info],
23
+ device: @request[:device],
24
+ }
25
+
26
+ if @experiment
27
+ log_req[:cohort_membership] = [@experiment]
28
+ end
29
+
30
+ # Log request allows for multiple requests but here we only send one.
31
+ if include_delivery_log
32
+ request[:request_id] = request[:request_id] || @id_generator.newID
33
+ # Remove redundant fields from `request` since they're already on the LogRequest.
34
+ stripped_request = @request.clone
35
+ stripped_request.delete(:platform_id)
36
+ stripped_request.delete(:user_info)
37
+ stripped_request.delete(:timing)
38
+ stripped_request.delete(:device)
39
+ stripped_request.delete(:client_info)
40
+
41
+ log_req[:delivery_log] = [{
42
+ execution: {
43
+ execution_server: exec_server,
44
+ server_version: Promoted::Ruby::Client::SERVER_VERSION
45
+ },
46
+ request: stripped_request,
47
+ response: {
48
+ insertion: @response_insertions
49
+ }
50
+ }]
51
+ end
52
+ log_req.clean!
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ require "promoted/ruby/client/constants"
60
+ require "promoted/ruby/client/extensions"
61
+ require "promoted/ruby/client/id_generator"
@@ -50,11 +50,14 @@ module Promoted
50
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
- insertion = insertions[index]
54
- if insertion[:position] == nil
55
- insertion[:position] = offset
56
- end
57
- insertion_page[i] = insertion
53
+ request_insertion = insertions[index]
54
+ # Pager returns response insertions. Create a copy and fill in some of the fields.
55
+ response_insertion = Hash[]
56
+ response_insertion[:content_id] = request_insertion[:content_id]
57
+ response_insertion[:insertion_id] = request_insertion[:insertion_id]
58
+ # TODO - implement retrieval_start.
59
+ response_insertion[:position] = offset
60
+ insertion_page[i] = response_insertion
58
61
  index = index + 1
59
62
  offset = offset + 1
60
63
  }
@@ -49,7 +49,6 @@ module Promoted
49
49
  return @experiment
50
50
  end
51
51
 
52
- # Only used in delivery
53
52
  def delivery_request_params
54
53
  params = {
55
54
  user_info: user_info,
@@ -70,93 +69,12 @@ module Promoted
70
69
  params.clean!
71
70
  end
72
71
 
73
- # Only used in delivery
74
- # Maps the response insertions to the full insertions and re-insert the properties bag
75
- # to the responses.
76
- def fill_details_from_response response_insertions
77
- if !response_insertions then
78
- response_insertions = []
79
- end
80
-
81
- props = @insertion.each_with_object({}) do |insertion, hash|
82
- if insertion.has_key?(:properties)
83
- # Don't add nil properties to response insertions.
84
- hash[insertion[:content_id]] = insertion[:properties]
85
- end
86
- end
87
-
88
- filled_in_copy = []
89
- response_insertions.each do |resp_insertion|
90
- copied_insertion = resp_insertion.clone
91
- if copied_insertion.has_key?(:content_id) && props.has_key?(copied_insertion[:content_id])
92
- copied_insertion[:properties] = props[resp_insertion[:content_id]]
93
- end
94
- filled_in_copy << copied_insertion
95
- end
96
-
97
- filled_in_copy
98
- end
99
-
100
- def log_request_params(include_delivery_log:, exec_server:)
101
- params = {
102
- user_info: user_info,
103
- timing: timing,
104
- client_info: merge_client_info_defaults,
105
- device: @device,
106
- }
107
-
108
- if @experiment
109
- params[:cohort_membership] = [@experiment]
110
- end
111
-
112
- # Log request allows for multiple requests but here we only send one.
113
- if include_delivery_log
114
- request[:request_id] = request[:request_id] || @id_generator.newID
115
-
116
- params[:delivery_log] = [{
117
- execution: {
118
- execution_server: exec_server,
119
- server_version: Promoted::Ruby::Client::SERVER_VERSION
120
- },
121
- request: request,
122
- response: {
123
- insertion: response_insertion
124
- }
125
- }]
126
-
127
- add_missing_insertion_ids! params[:delivery_log][0][:response][:insertion]
128
- end
129
-
130
- params.clean!
131
- end
132
-
133
72
  def ensure_client_timestamp
134
73
  if timing[:client_log_timestamp].nil?
135
74
  timing[:client_log_timestamp] = (Time.now.to_f * 1000).to_i
136
75
  end
137
76
  end
138
77
 
139
- def response_insertion
140
- @response_insertions = []
141
- paging = request[:paging] || {}
142
- size = paging[:size] ? paging[:size].to_i : 0
143
- if size <= 0
144
- size = insertion.length()
145
- end
146
- offset = paging[:offset] ? paging[:offset].to_i : 0
147
-
148
- insertion.each_with_index do |insertion_obj, index|
149
- # TODO - this does not look performant.
150
- break if @response_insertions.length() >= size
151
- response_insertion = Hash[]
152
- response_insertion[:content_id] = insertion_obj[:content_id]
153
- response_insertion[:position] = offset + index
154
- response_insertion[:insertion_id] = insertion_obj[:insertion_id]
155
- @response_insertions << response_insertion.clean!
156
- end
157
- @response_insertions
158
- end
159
-
160
78
  def add_missing_insertion_ids! insertions
161
79
  insertions.each do |insertion|
162
80
  insertion[:insertion_id] = @id_generator.newID if not insertion[:insertion_id]
@@ -31,10 +31,10 @@ module Promoted
31
31
  end
32
32
  end
33
33
  sym_hash
34
- rescue => e
34
+ rescue
35
35
  raise 'Unable to parse args. Please pass correct arguments. Must be JSON'
36
- end
37
36
  end
37
+ end
38
38
  end
39
- end
39
+ end
40
40
  end
@@ -116,6 +116,24 @@ module Promoted
116
116
  end
117
117
  end
118
118
 
119
+ def validate_response!(res)
120
+ validate_fields!(
121
+ res,
122
+ "response",
123
+ [
124
+ {
125
+ :name => :request_id,
126
+ :required => true,
127
+ :type => String
128
+ }
129
+ ]
130
+ )
131
+
132
+ if !res.key?(:insertion) then
133
+ res[:insertion] = []
134
+ end
135
+ end
136
+
119
137
  # TODO - delete?
120
138
  def validate_metrics_request!(metrics_req)
121
139
  validate_fields!(
@@ -1,7 +1,7 @@
1
1
  module Promoted
2
2
  module Ruby
3
3
  module Client
4
- VERSION = "1.0.0"
4
+ VERSION = "2.0.0"
5
5
  SERVER_VERSION = "rb." + VERSION
6
6
  end
7
7
  end
@@ -135,10 +135,10 @@ module Promoted
135
135
  if @perform_checks
136
136
  perform_common_checks!(args)
137
137
  if !only_log && args[:insertion_page_type] == Promoted::Ruby::Client::INSERTION_PAGING_TYPE['PRE_PAGED'] then
138
- err = DeliveryInsertionPageType.new
139
- @logger.error(err) if @logger
140
- raise err
141
- end
138
+ err = DeliveryInsertionPageType.new
139
+ @logger.error(err) if @logger
140
+ raise err
141
+ end
142
142
 
143
143
  if should_send_shadow_traffic && args[:insertion_page_type] != Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'] then
144
144
  should_send_shadow_traffic = false
@@ -179,6 +179,7 @@ module Promoted
179
179
  delivery_request_params = delivery_request_builder.delivery_request_params
180
180
  begin
181
181
  response = send_request(delivery_request_params, @delivery_endpoint, @delivery_timeout_millis, @delivery_api_key, headers)
182
+ @validator.validate_response!(response)
182
183
  rescue StandardError => err
183
184
  # Currently we don't propagate errors to the SDK caller, but rather default to returning
184
185
  # the request insertions.
@@ -191,8 +192,7 @@ module Promoted
191
192
  end
192
193
 
193
194
  insertions_from_delivery = (response != nil && !deliver_err);
194
- response_insertions = delivery_request_builder.fill_details_from_response(
195
- response && response[:insertion] || [])
195
+ response_insertions = response && response[:insertion] || []
196
196
  end
197
197
 
198
198
  should_send_shadow_traffic &&= should_send_as_shadow_traffic?
@@ -201,33 +201,24 @@ module Promoted
201
201
  deliver_shadow_traffic args, headers
202
202
  end
203
203
 
204
- request_to_log = nil
205
204
  if !insertions_from_delivery then
206
- request_to_log = delivery_request_builder.request
207
205
  response_insertions = build_sdk_response_insertions(delivery_request_builder)
208
206
  end
209
207
 
210
208
  log_req = nil
211
209
  exec_server = (insertions_from_delivery ? Promoted::Ruby::Client::EXECUTION_SERVER['API'] : Promoted::Ruby::Client::EXECUTION_SERVER['SDK'])
212
-
213
- # We only return a log request if there's a request or cohort to log.
214
- if request_to_log || cohort_membership_to_log
215
- log_request_builder = RequestBuilder.new
216
- log_request = {
217
- :insertion => response_insertions,
218
- :experiment => cohort_membership_to_log,
219
- :request => request_to_log
220
- }
221
- log_request_builder.set_request_params(log_request)
222
210
 
223
- # We can't count on these being set already since request_to_log may be nil.
224
- log_request_builder.platform_id = delivery_request_builder.platform_id
225
- log_request_builder.timing = delivery_request_builder.timing
226
- log_request_builder.user_info = delivery_request_builder.user_info
211
+ # We only return a log request if there's a request or cohort to log.
212
+ if !insertions_from_delivery || cohort_membership_to_log
213
+ log_request_builder = LogRequestBuilder.new
214
+ # TODO - make this more efficient.
215
+ log_request_builder.request = delivery_request_builder.delivery_request_params
216
+ log_request_builder.response_insertions = response_insertions
217
+ log_request_builder.experiment = cohort_membership_to_log
227
218
 
228
219
  # On a successful delivery request, we don't log the insertions
229
220
  # or the request since they are logged on the server-side.
230
- log_req = log_request_builder.log_request_params(
221
+ log_req = log_request_builder.log_request(
231
222
  include_delivery_log: !insertions_from_delivery,
232
223
  exec_server: exec_server)
233
224
  end
@@ -346,6 +337,7 @@ module Promoted
346
337
  response = nil
347
338
  begin
348
339
  response = send_request(delivery_request_params, @delivery_endpoint, @delivery_timeout_millis, @delivery_api_key, headers, @async_shadow_traffic)
340
+ @validator.validate_response!(response)
349
341
  rescue StandardError => err
350
342
  @logger.warn("Shadow traffic call failed with #{err}") if @logger
351
343
  return
@@ -384,6 +376,7 @@ module Promoted
384
376
  end
385
377
 
386
378
  # dependent /libs
379
+ require "promoted/ruby/client/log_request_builder"
387
380
  require "promoted/ruby/client/request_builder"
388
381
  require "promoted/ruby/client/pager"
389
382
  require "promoted/ruby/client/sampler"
@@ -14,7 +14,9 @@ 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"] = "http://rubygems.org/gems/promoted-ruby-client"
17
+ # Uncomment if you want to push to a custom host
18
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
19
+
18
20
  spec.metadata["homepage_uri"] = spec.homepage
19
21
  spec.metadata["source_code_uri"] = "https://github.com/promotedai/promoted-ruby-client"
20
22
  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: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - scottmcmaster
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-01-02 00:00:00.000000000 Z
11
+ date: 2023-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -139,6 +139,7 @@ files:
139
139
  - lib/promoted/ruby/client/extensions.rb
140
140
  - lib/promoted/ruby/client/faraday_http_client.rb
141
141
  - lib/promoted/ruby/client/id_generator.rb
142
+ - lib/promoted/ruby/client/log_request_builder.rb
142
143
  - lib/promoted/ruby/client/pager.rb
143
144
  - lib/promoted/ruby/client/request_builder.rb
144
145
  - lib/promoted/ruby/client/sampler.rb
@@ -153,7 +154,7 @@ metadata:
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
156
- post_install_message:
157
+ post_install_message:
157
158
  rdoc_options: []
158
159
  require_paths:
159
160
  - lib
@@ -168,8 +169,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
169
  - !ruby/object:Gem::Version
169
170
  version: '0'
170
171
  requirements: []
171
- rubygems_version: 3.0.3
172
- signing_key:
172
+ rubygems_version: 3.4.9
173
+ signing_key:
173
174
  specification_version: 4
174
175
  summary: A Ruby Client to contact Promoted APIs.
175
176
  test_files: []