promoted-ruby-client 1.0.0 → 2.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
  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: []