promoted-ruby-client 0.1.5 → 0.1.9
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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +6 -6
- data/dev.md +2 -3
- data/lib/promoted/ruby/client.rb +97 -51
- data/lib/promoted/ruby/client/id_generator.rb +15 -0
- data/lib/promoted/ruby/client/pager.rb +57 -0
- data/lib/promoted/ruby/client/request_builder.rb +46 -9
- data/lib/promoted/ruby/client/version.rb +1 -1
- metadata +4 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: efa5db6f158b8ab87cb8d17020d34e2d797025ea6b2b08ee032eb4be0f9ac715
         | 
| 4 | 
            +
              data.tar.gz: 957e394b3e61cdfc55b68650392a158a492b0d5904df1bd88e17c9378078161b
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: a30a50a35881680fda99cb355d7469e1e805f5199db86f32713e3f803c68113e8932ae2458f3359c78f323e6c0914a974cf1579967a8a8760b7d48b0064dade9
         | 
| 7 | 
            +
              data.tar.gz: fa2dde1f6bc78733f3db6fb8a37e19b8b9a00d3531d1508fc3fce3045f87360f5047086f6446906f8b9aa56dc09b2d217d076ea1c242210d098745aa2eb400da
         | 
    
        data/Gemfile.lock
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -28,10 +28,10 @@ This client will suffice for building log requests. To send actually send traffi | |
| 28 28 |  | 
| 29 29 | 
             
            ```rb
         | 
| 30 30 | 
             
            client = Promoted::Ruby::Client::PromotedClient.new({
         | 
| 31 | 
            -
              :metrics_endpoint  | 
| 32 | 
            -
              :delivery_endpoint  | 
| 33 | 
            -
              :metrics_api_key  | 
| 34 | 
            -
              :delivery_api_key  | 
| 31 | 
            +
              :metrics_endpoint => "https://<get this from Promoted>",
         | 
| 32 | 
            +
              :delivery_endpoint => "https://<get this from Promoted>",
         | 
| 33 | 
            +
              :metrics_api_key => "<get this from Promoted>",
         | 
| 34 | 
            +
              :delivery_api_key => "<get this from Promoted>"
         | 
| 35 35 | 
             
            })
         | 
| 36 36 | 
             
            ```
         | 
| 37 37 |  | 
| @@ -88,7 +88,7 @@ Field Name | Type | Optional? | Description | |
| 88 88 | 
             
            ---------- | ---- | --------- | -----------
         | 
| 89 89 | 
             
            ```:user_info``` | UserInfo | Yes | The user info structure.
         | 
| 90 90 | 
             
            ```:insertion_id``` | String | Yes | Generated by the SDK (*do not set*)
         | 
| 91 | 
            -
            ```:request_id``` | String | Yes | Generated by the SDK (*do not set*)
         | 
| 91 | 
            +
            ```:request_id``` | String | Yes | Generated by the SDK when needed (*do not set*)
         | 
| 92 92 | 
             
            ```:content_id``` | String | No | Identifier for the content to be shown, must be set.
         | 
| 93 93 | 
             
            ```:properties``` | Properties | Yes | Any additional custom properties to associate. For v1 integrations, it is fine not to fill in all the properties.
         | 
| 94 94 |  | 
| @@ -101,7 +101,7 @@ A request for content insertions. | |
| 101 101 | 
             
            Field Name | Type | Optional? | Description
         | 
| 102 102 | 
             
            ---------- | ---- | --------- | -----------
         | 
| 103 103 | 
             
            ```:user_info``` | UserInfo | Yes | The user info structure.
         | 
| 104 | 
            -
            ```:request_id``` | String | Yes | Generated by the SDK (*do not set*)
         | 
| 104 | 
            +
            ```:request_id``` | String | Yes | Generated by the SDK when needed (*do not set*)
         | 
| 105 105 | 
             
            ```:use_case``` | String | Yes | One of the use case values, i.e. 'FEED' (see [constants.rb](https://github.com/promotedai/promoted-ruby-client/blob/main/lib/promoted/ruby/client/constants.rb)).
         | 
| 106 106 | 
             
            ```:properties``` | Properties | Yes | Any additional custom properties to associate.
         | 
| 107 107 | 
             
            ```:paging``` | Paging | Yes | Paging parameters (see TODO)
         | 
    
        data/dev.md
    CHANGED
    
    | @@ -1,9 +1,8 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
            ## Deploy
         | 
| 1 | 
            +
            # Deploy
         | 
| 3 2 |  | 
| 4 3 | 
             
            1. Update version number.
         | 
| 5 4 | 
             
            2. Get credentials for deployment from 1password.
         | 
| 6 5 | 
             
            3. Modify `promoted-ruby-client.gemspec`'s push block.
         | 
| 7 6 | 
             
            4. Run `gem build promoted-ruby-client.gemspec` to generate `gem`.
         | 
| 8 | 
            -
            5. Run (using new output) `gem push promoted-ruby-client-0.1. | 
| 7 | 
            +
            5. Run (using new output) `gem push promoted-ruby-client-0.1.9.gem`
         | 
| 9 8 | 
             
            6. Update README with new version.
         | 
    
        data/lib/promoted/ruby/client.rb
    CHANGED
    
    | @@ -19,8 +19,16 @@ 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
         | 
| 22 | 
            +
                                :default_request_headers, :http_client, :logger, :shadow_traffic_delivery_percent, :async_shadow_traffic
         | 
| 23 | 
            +
                                
         | 
| 24 | 
            +
                    attr_accessor :request_logging_on, :enabled
         | 
| 23 25 |  | 
| 26 | 
            +
                    ##
         | 
| 27 | 
            +
                    # Whether or not the client is currently enabled for execution.
         | 
| 28 | 
            +
                    def enabled?
         | 
| 29 | 
            +
                      @enabled
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
             | 
| 24 32 | 
             
                    ##            
         | 
| 25 33 | 
             
                    # A common compact method implementation.
         | 
| 26 34 | 
             
                    def self.copy_and_remove_properties
         | 
| @@ -39,7 +47,8 @@ module Promoted | |
| 39 47 | 
             
                        @perform_checks = params[:perform_checks]
         | 
| 40 48 | 
             
                      end
         | 
| 41 49 |  | 
| 42 | 
            -
                      @logger | 
| 50 | 
            +
                      @logger               = params[:logger] # Example:  Logger.new(STDERR, :progname => "promotedai")
         | 
| 51 | 
            +
                      @request_logging_on   = params[:request_logging_on] || false
         | 
| 43 52 |  | 
| 44 53 | 
             
                      @default_request_headers = params[:default_request_headers] || {}
         | 
| 45 54 | 
             
                      @metrics_api_key = params[:metrics_api_key] || ''
         | 
| @@ -52,6 +61,7 @@ module Promoted | |
| 52 61 | 
             
                      raise ArgumentError.new("Invalid shadow_traffic_delivery_percent, must be between 0 and 1") if @shadow_traffic_delivery_percent < 0 || @shadow_traffic_delivery_percent > 1.0
         | 
| 53 62 |  | 
| 54 63 | 
             
                      @sampler = Sampler.new
         | 
| 64 | 
            +
                      @pager   = Pager.new
         | 
| 55 65 |  | 
| 56 66 | 
             
                      # HTTP Client creation
         | 
| 57 67 | 
             
                      @delivery_endpoint = params[:delivery_endpoint] || DEFAULT_DELIVERY_ENDPOINT
         | 
| @@ -66,21 +76,36 @@ module Promoted | |
| 66 76 | 
             
                      @http_client = FaradayHTTPClient.new
         | 
| 67 77 | 
             
                      @validator = Promoted::Ruby::Client::Validator.new
         | 
| 68 78 |  | 
| 69 | 
            -
                       | 
| 70 | 
            -
                       | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 79 | 
            +
                      @async_shadow_traffic = true
         | 
| 80 | 
            +
                      if params[:async_shadow_traffic] != nil
         | 
| 81 | 
            +
                        @async_shadow_traffic = params[:async_shadow_traffic] || false
         | 
| 82 | 
            +
                      end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                      @pool = nil
         | 
| 85 | 
            +
                      if @async_shadow_traffic
         | 
| 86 | 
            +
                        # Thread pool to process delivery of shadow traffic. Will silently drop excess requests beyond the queue
         | 
| 87 | 
            +
                        # size, and silently eat errors on the background threads.
         | 
| 88 | 
            +
                        @pool = Concurrent::ThreadPoolExecutor.new(
         | 
| 89 | 
            +
                          min_threads: 0,
         | 
| 90 | 
            +
                          max_threads: 10,
         | 
| 91 | 
            +
                          max_queue: 100,
         | 
| 92 | 
            +
                          fallback_policy: :discard
         | 
| 93 | 
            +
                        )
         | 
| 94 | 
            +
                      end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                      @enabled = true
         | 
| 97 | 
            +
                      if params[:enabled] != nil
         | 
| 98 | 
            +
                        @enabled = params[:enabled] || false
         | 
| 99 | 
            +
                      end
         | 
| 77 100 | 
             
                    end
         | 
| 78 101 |  | 
| 79 102 | 
             
                    ##
         | 
| 80 103 | 
             
                    # Politely shut down a Promoted client.
         | 
| 81 104 | 
             
                    def close
         | 
| 82 | 
            -
                      @pool | 
| 83 | 
            -
             | 
| 105 | 
            +
                      if @pool
         | 
| 106 | 
            +
                        @pool.shutdown
         | 
| 107 | 
            +
                        @pool.wait_for_termination
         | 
| 108 | 
            +
                      end
         | 
| 84 109 | 
             
                    end
         | 
| 85 110 |  | 
| 86 111 | 
             
                    ##
         | 
| @@ -88,19 +113,34 @@ module Promoted | |
| 88 113 | 
             
                    def deliver args, headers={}
         | 
| 89 114 | 
             
                      args = Promoted::Ruby::Client::Util.translate_args(args)
         | 
| 90 115 |  | 
| 116 | 
            +
                      # Respect the enabled state
         | 
| 117 | 
            +
                      if !@enabled
         | 
| 118 | 
            +
                        return {
         | 
| 119 | 
            +
                          insertion: @pager.apply_paging(args[:full_insertion], Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'], args[:request][:paging])
         | 
| 120 | 
            +
                          # No log request returned when disabled
         | 
| 121 | 
            +
                        }
         | 
| 122 | 
            +
                      end
         | 
| 123 | 
            +
                      
         | 
| 91 124 | 
             
                      delivery_request_builder = RequestBuilder.new
         | 
| 92 125 | 
             
                      delivery_request_builder.set_request_params(args)
         | 
| 93 126 |  | 
| 94 127 | 
             
                      perform_common_checks!(args) if @perform_checks
         | 
| 95 128 |  | 
| 96 | 
            -
                       | 
| 129 | 
            +
                      delivery_request_builder.ensure_client_timestamp
         | 
| 97 130 |  | 
| 98 131 | 
             
                      response_insertions = []
         | 
| 99 132 | 
             
                      cohort_membership_to_log = nil
         | 
| 100 | 
            -
                       | 
| 133 | 
            +
                      insertions_from_delivery = false
         | 
| 101 134 |  | 
| 102 135 | 
             
                      only_log = delivery_request_builder.only_log != nil ? delivery_request_builder.only_log : @default_only_log
         | 
| 103 136 | 
             
                      deliver_err = false
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                      if !@pager.validate_paging(delivery_request_builder.full_insertion, delivery_request_builder.request[:paging])
         | 
| 139 | 
            +
                        # Invalid input, log and do SDK-side delivery.
         | 
| 140 | 
            +
                        @logger.warn("Invalid paging parameters") if @logger
         | 
| 141 | 
            +
                        only_log = true
         | 
| 142 | 
            +
                      end
         | 
| 143 | 
            +
             | 
| 104 144 | 
             
                      if !only_log
         | 
| 105 145 | 
             
                        cohort_membership_to_log = delivery_request_builder.new_cohort_membership_to_log
         | 
| 106 146 |  | 
| @@ -117,22 +157,16 @@ module Promoted | |
| 117 157 | 
             
                            @logger.error("Error calling delivery: " + err.message) if @logger
         | 
| 118 158 | 
             
                          end
         | 
| 119 159 |  | 
| 120 | 
            -
                           | 
| 160 | 
            +
                          insertions_from_delivery = (response != nil && !deliver_err);
         | 
| 121 161 | 
             
                          response_insertions = delivery_request_builder.fill_details_from_response(
         | 
| 122 | 
            -
                            response ? response[:insertion] :  | 
| 162 | 
            +
                            response ? response[:insertion] : [])
         | 
| 123 163 | 
             
                        end
         | 
| 124 164 | 
             
                      end
         | 
| 125 165 |  | 
| 126 166 | 
             
                      request_to_log = nil
         | 
| 127 | 
            -
                      if ! | 
| 167 | 
            +
                      if !insertions_from_delivery then
         | 
| 128 168 | 
             
                        request_to_log = delivery_request_builder.request
         | 
| 129 | 
            -
                         | 
| 130 | 
            -
                        response_insertions = size != nil ? delivery_request_builder.full_insertion[0..size] : delivery_request_builder.full_insertion
         | 
| 131 | 
            -
                      end
         | 
| 132 | 
            -
             | 
| 133 | 
            -
                      if request_to_log
         | 
| 134 | 
            -
                        request_to_log[:request_id] = SecureRandom.uuid if not request_to_log[:request_id]
         | 
| 135 | 
            -
                        add_missing_ids_on_insertions! request_to_log, response_insertions
         | 
| 169 | 
            +
                        response_insertions = @pager.apply_paging(delivery_request_builder.full_insertion, Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'], delivery_request_builder.request[:paging])
         | 
| 136 170 | 
             
                      end
         | 
| 137 171 |  | 
| 138 172 | 
             
                      log_req = nil
         | 
| @@ -150,14 +184,12 @@ module Promoted | |
| 150 184 | 
             
                        log_request_builder.platform_id = delivery_request_builder.platform_id
         | 
| 151 185 | 
             
                        log_request_builder.timing      = delivery_request_builder.timing
         | 
| 152 186 | 
             
                        log_request_builder.user_info   = delivery_request_builder.user_info
         | 
| 153 | 
            -
                        pre_delivery_fillin_fields log_request_builder
         | 
| 154 | 
            -
             | 
| 155 187 |  | 
| 156 188 | 
             
                        # On a successful delivery request, we don't log the insertions
         | 
| 157 189 | 
             
                        # or the request since they are logged on the server-side.
         | 
| 158 190 | 
             
                        log_req = log_request_builder.log_request_params(
         | 
| 159 | 
            -
                          include_insertions: ! | 
| 160 | 
            -
                          include_request: ! | 
| 191 | 
            +
                          include_insertions: !insertions_from_delivery, 
         | 
| 192 | 
            +
                          include_request: !insertions_from_delivery)
         | 
| 161 193 | 
             
                      end
         | 
| 162 194 |  | 
| 163 195 | 
             
                      client_response = {
         | 
| @@ -173,6 +205,12 @@ module Promoted | |
| 173 205 | 
             
                    def prepare_for_logging args, headers={}
         | 
| 174 206 | 
             
                      args = Promoted::Ruby::Client::Util.translate_args(args)
         | 
| 175 207 |  | 
| 208 | 
            +
                      if !@enabled
         | 
| 209 | 
            +
                        return {
         | 
| 210 | 
            +
                          insertion: args[:full_insertion]
         | 
| 211 | 
            +
                        }
         | 
| 212 | 
            +
                      end
         | 
| 213 | 
            +
             | 
| 176 214 | 
             
                      log_request_builder = RequestBuilder.new
         | 
| 177 215 |  | 
| 178 216 | 
             
                      # Note: This method expects as JSON (string keys) but internally, RequestBuilder
         | 
| @@ -188,7 +226,7 @@ module Promoted | |
| 188 226 | 
             
                        end
         | 
| 189 227 | 
             
                      end
         | 
| 190 228 |  | 
| 191 | 
            -
                       | 
| 229 | 
            +
                      log_request_builder.ensure_client_timestamp
         | 
| 192 230 |  | 
| 193 231 | 
             
                      if !shadow_traffic_err && should_send_as_shadow_traffic?
         | 
| 194 232 | 
             
                        deliver_shadow_traffic args, headers
         | 
| @@ -211,29 +249,38 @@ module Promoted | |
| 211 249 | 
             
                    private
         | 
| 212 250 |  | 
| 213 251 | 
             
                    def send_request payload, endpoint, timeout_millis, api_key, headers={}, send_async=false
         | 
| 252 | 
            +
                      resp = nil
         | 
| 253 | 
            +
             | 
| 214 254 | 
             
                      headers["x-api-key"] = api_key
         | 
| 215 255 | 
             
                      use_headers = @default_request_headers.merge headers
         | 
| 216 256 |  | 
| 217 | 
            -
                      if  | 
| 257 | 
            +
                      if @request_logging_on && @logger
         | 
| 258 | 
            +
                        @logger.info("promotedai") {
         | 
| 259 | 
            +
                          "Sending #{payload.to_json} to #{endpoint}"
         | 
| 260 | 
            +
                        }
         | 
| 261 | 
            +
                      end
         | 
| 262 | 
            +
             | 
| 263 | 
            +
                      if send_async && @pool
         | 
| 218 264 | 
             
                        @pool.post do
         | 
| 219 | 
            -
                           | 
| 265 | 
            +
                          start_time = Time.now.to_i
         | 
| 266 | 
            +
                          begin
         | 
| 267 | 
            +
                            resp = @http_client.send(endpoint, timeout_millis, payload, use_headers)
         | 
| 268 | 
            +
                          rescue Faraday::Error => err
         | 
| 269 | 
            +
                            @logger.warn("Deliver call failed with #{err}") if @logger
         | 
| 270 | 
            +
                            return
         | 
| 271 | 
            +
                          end
         | 
| 272 | 
            +
                          ellapsed_time = Time.now.to_i - start_time
         | 
| 273 | 
            +
                          @logger.info("Deliver call completed in #{ellapsed_time} ms") if @logger
         | 
| 220 274 | 
             
                        end
         | 
| 221 275 | 
             
                      else
         | 
| 222 276 | 
             
                        begin
         | 
| 223 | 
            -
                          @http_client.send(endpoint, timeout_millis, payload, use_headers)
         | 
| 277 | 
            +
                          resp = @http_client.send(endpoint, timeout_millis, payload, use_headers)
         | 
| 224 278 | 
             
                        rescue Faraday::Error => err
         | 
| 225 279 | 
             
                          raise EndpointError.new(err)
         | 
| 226 280 | 
             
                        end
         | 
| 227 281 | 
             
                      end
         | 
| 228 | 
            -
                    end
         | 
| 229 282 |  | 
| 230 | 
            -
             | 
| 231 | 
            -
                    def add_missing_ids_on_insertions! request, insertions
         | 
| 232 | 
            -
                      insertions.each do |insertion|
         | 
| 233 | 
            -
                        insertion[:insertion_id] = SecureRandom.uuid if not insertion[:insertion_id]
         | 
| 234 | 
            -
                        insertion[:session_id] = request[:session_id] if request[:session_id]
         | 
| 235 | 
            -
                        insertion[:request_id] = request[:request_id] if request[:request_id]
         | 
| 236 | 
            -
                      end
         | 
| 283 | 
            +
                      return resp
         | 
| 237 284 | 
             
                    end
         | 
| 238 285 |  | 
| 239 286 | 
             
                    def should_send_as_shadow_traffic?
         | 
| @@ -250,8 +297,12 @@ module Promoted | |
| 250 297 | 
             
                      delivery_request_params = delivery_request_builder.delivery_request_params(should_compact: false)
         | 
| 251 298 | 
             
                      delivery_request_params[:client_info][:traffic_type] = Promoted::Ruby::Client::TRAFFIC_TYPE['SHADOW']
         | 
| 252 299 |  | 
| 253 | 
            -
                      # Call Delivery API  | 
| 254 | 
            -
                       | 
| 300 | 
            +
                      # Call Delivery API and log/ignore errors.
         | 
| 301 | 
            +
                      begin
         | 
| 302 | 
            +
                        send_request(delivery_request_params, @delivery_endpoint, @delivery_timeout_millis, @delivery_api_key, headers, true)
         | 
| 303 | 
            +
                      rescue StandardError => err
         | 
| 304 | 
            +
                        @logger.warn("Shadow traffic call failed with #{err}") if @logger
         | 
| 305 | 
            +
                      end
         | 
| 255 306 | 
             
                    end
         | 
| 256 307 |  | 
| 257 308 | 
             
                    def perform_common_checks!(req)
         | 
| @@ -272,14 +323,7 @@ module Promoted | |
| 272 323 | 
             
                        return true if !cohort_membership[:arm]
         | 
| 273 324 | 
             
                        return cohort_membership[:arm] != Promoted::Ruby::Client::COHORT_ARM['CONTROL']
         | 
| 274 325 | 
             
                      end
         | 
| 275 | 
            -
                    end
         | 
| 276 | 
            -
                    
         | 
| 277 | 
            -
                    # TODO: This probably just goes better in the RequestBuilder class.
         | 
| 278 | 
            -
                    def pre_delivery_fillin_fields(log_request_builder)
         | 
| 279 | 
            -
                      if log_request_builder.timing[:client_log_timestamp].nil?
         | 
| 280 | 
            -
                        log_request_builder.timing[:client_log_timestamp] = Time.now.to_i
         | 
| 281 | 
            -
                      end
         | 
| 282 | 
            -
                    end
         | 
| 326 | 
            +
                    end        
         | 
| 283 327 | 
             
                  end
         | 
| 284 328 | 
             
                end
         | 
| 285 329 | 
             
              end
         | 
| @@ -287,7 +331,9 @@ end | |
| 287 331 |  | 
| 288 332 | 
             
            # dependent /libs
         | 
| 289 333 | 
             
            require "promoted/ruby/client/request_builder"
         | 
| 334 | 
            +
            require "promoted/ruby/client/pager"
         | 
| 290 335 | 
             
            require "promoted/ruby/client/sampler"
         | 
| 291 336 | 
             
            require "promoted/ruby/client/util"
         | 
| 292 337 | 
             
            require "promoted/ruby/client/validator"
         | 
| 293 | 
            -
            require 'securerandom'
         | 
| 338 | 
            +
            require 'securerandom'
         | 
| 339 | 
            +
            require 'time'
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            module Promoted
         | 
| 2 | 
            +
                module Ruby
         | 
| 3 | 
            +
                  module Client
         | 
| 4 | 
            +
                    class Pager
         | 
| 5 | 
            +
                        def validate_paging (insertions, paging)
         | 
| 6 | 
            +
                          if paging && paging[:offset]
         | 
| 7 | 
            +
                            return paging[:offset] < insertions.length
         | 
| 8 | 
            +
                          end
         | 
| 9 | 
            +
                          return true          
         | 
| 10 | 
            +
                        end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                        def apply_paging (insertions, insertion_page_type, paging = nil)
         | 
| 13 | 
            +
                          # This is invalid input, stop it before it goes to the server.
         | 
| 14 | 
            +
                          if !validate_paging(insertions, paging)
         | 
| 15 | 
            +
                            return []
         | 
| 16 | 
            +
                          end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                          if !paging
         | 
| 19 | 
            +
                            paging = {
         | 
| 20 | 
            +
                              :offset => 0,
         | 
| 21 | 
            +
                              :size => insertions.length
         | 
| 22 | 
            +
                            }
         | 
| 23 | 
            +
                          end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                          offset = [0, paging[:offset]].max
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                          index = offset
         | 
| 28 | 
            +
                          if insertion_page_type == Promoted::Ruby::Client::INSERTION_PAGING_TYPE['PRE_PAGED']
         | 
| 29 | 
            +
                            # When insertions are pre-paged, we don't use offset to
         | 
| 30 | 
            +
                            # window into the provided insertions, although we do use it when
         | 
| 31 | 
            +
                            # assigning positions.
         | 
| 32 | 
            +
                            index = 0
         | 
| 33 | 
            +
                          end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                          size = paging[:size]
         | 
| 36 | 
            +
                          if size <= 0
         | 
| 37 | 
            +
                            size = insertions.length
         | 
| 38 | 
            +
                          end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                          final_insertion_size = [size, insertions.length].min
         | 
| 41 | 
            +
                          insertion_page = Array.new(final_insertion_size)
         | 
| 42 | 
            +
                          0.upto(final_insertion_size - 1) {|i|
         | 
| 43 | 
            +
                            insertion = insertions[index]
         | 
| 44 | 
            +
                            if insertion[:position] == nil
         | 
| 45 | 
            +
                              insertion[:position] = offset
         | 
| 46 | 
            +
                            end
         | 
| 47 | 
            +
                            insertion_page[i] = insertion
         | 
| 48 | 
            +
                            index = index + 1
         | 
| 49 | 
            +
                            offset = offset + 1
         | 
| 50 | 
            +
                          }
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                          return insertion_page
         | 
| 53 | 
            +
                        end
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
               end
         | 
| 57 | 
            +
            end
         | 
| @@ -8,7 +8,13 @@ module Promoted | |
| 8 8 |  | 
| 9 9 | 
             
                    attr_accessor :timing, :user_info, :platform_id
         | 
| 10 10 |  | 
| 11 | 
            -
                    def initialize | 
| 11 | 
            +
                    def initialize args = {}
         | 
| 12 | 
            +
                      if args[:id_generator]
         | 
| 13 | 
            +
                        @id_generator = args[:id_generator]
         | 
| 14 | 
            +
                      else
         | 
| 15 | 
            +
                        @id_generator = IdGenerator.new
         | 
| 16 | 
            +
                      end
         | 
| 17 | 
            +
                    end
         | 
| 12 18 |  | 
| 13 19 | 
             
                    # Populates request parameters from the given arguments, presumed to be a hash of symbols.
         | 
| 14 20 | 
             
                    def set_request_params args = {}
         | 
| @@ -21,11 +27,13 @@ module Promoted | |
| 21 27 | 
             
                      @view_id                 = request[:view_id]
         | 
| 22 28 | 
             
                      @use_case                = Promoted::Ruby::Client::USE_CASES[request[:use_case]] || Promoted::Ruby::Client::USE_CASES['UNKNOWN_USE_CASE']
         | 
| 23 29 | 
             
                      @full_insertion          = args[:full_insertion]
         | 
| 24 | 
            -
                      @request_id              = SecureRandom.uuid
         | 
| 25 30 | 
             
                      @user_info               = request[:user_info] || { :user_id => nil, :log_user_id => nil}
         | 
| 26 31 | 
             
                      @timing                  = request[:timing] || { :client_log_timestamp => Time.now.to_i }
         | 
| 27 32 | 
             
                      @to_compact_metrics_insertion_func       = args[:to_compact_metrics_insertion_func]
         | 
| 28 33 | 
             
                      @to_compact_delivery_insertion_func      = args[:to_compact_delivery_insertion_func]
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                      # If the user didn't create a client request id, we do it for them.
         | 
| 36 | 
            +
                      request[:client_request_id] = request[:client_request_id] || @id_generator.newID
         | 
| 29 37 | 
             
                    end
         | 
| 30 38 |  | 
| 31 39 | 
             
                    # Only used in delivery
         | 
| @@ -48,10 +56,16 @@ module Promoted | |
| 48 56 | 
             
                      params = {
         | 
| 49 57 | 
             
                        user_info: user_info,
         | 
| 50 58 | 
             
                        timing: timing,
         | 
| 51 | 
            -
                         | 
| 52 | 
            -
                         | 
| 59 | 
            +
                        client_info: @client_info.merge({ :client_type => Promoted::Ruby::Client::CLIENT_TYPE['PLATFORM_SERVER'] }),
         | 
| 60 | 
            +
                        platform_id: @platform_id,
         | 
| 61 | 
            +
                        view_id: @view_id,
         | 
| 62 | 
            +
                        session_id: @session_id,
         | 
| 63 | 
            +
                        use_case: @use_case,
         | 
| 64 | 
            +
                        search_query: request[:search_query],
         | 
| 65 | 
            +
                        properties: request[:properties],
         | 
| 66 | 
            +
                        paging: request[:paging],
         | 
| 67 | 
            +
                        client_request_id: request[:client_request_id]
         | 
| 53 68 | 
             
                      }
         | 
| 54 | 
            -
                      params[:request] = request
         | 
| 55 69 | 
             
                      params[:insertion] = should_compact ? compact_delivery_insertions : full_insertion
         | 
| 56 70 |  | 
| 57 71 | 
             
                      params.clean!
         | 
| @@ -88,8 +102,17 @@ module Promoted | |
| 88 102 | 
             
                        cohort_membership: @experiment,
         | 
| 89 103 | 
             
                        client_info: @client_info
         | 
| 90 104 | 
             
                      }
         | 
| 91 | 
            -
             | 
| 92 | 
            -
                       | 
| 105 | 
            +
             | 
| 106 | 
            +
                      # Log request allows for multiple requests but here we only send one.
         | 
| 107 | 
            +
                      if include_request
         | 
| 108 | 
            +
                        request[:request_id] = request[:request_id] || @id_generator.newID
         | 
| 109 | 
            +
                        params[:request] = [request]
         | 
| 110 | 
            +
                      end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                      if include_insertions
         | 
| 113 | 
            +
                        params[:insertion] = compact_metrics_insertions if include_insertions
         | 
| 114 | 
            +
                        add_missing_ids_on_insertions! request, params[:insertion]
         | 
| 115 | 
            +
                      end
         | 
| 93 116 |  | 
| 94 117 | 
             
                      params.clean!
         | 
| 95 118 | 
             
                    end
         | 
| @@ -102,6 +125,12 @@ module Promoted | |
| 102 125 | 
             
                      end
         | 
| 103 126 | 
             
                    end
         | 
| 104 127 |  | 
| 128 | 
            +
                    def ensure_client_timestamp
         | 
| 129 | 
            +
                      if timing[:client_log_timestamp].nil?
         | 
| 130 | 
            +
                        timing[:client_log_timestamp] = Time.now.to_i
         | 
| 131 | 
            +
                      end
         | 
| 132 | 
            +
                    end
         | 
| 133 | 
            +
             | 
| 105 134 | 
             
                    # TODO: This looks overly complicated.
         | 
| 106 135 | 
             
                    def compact_metrics_insertions
         | 
| 107 136 | 
             
                      @insertion            = [] # insertion should be set according to the compact insertion
         | 
| @@ -120,7 +149,7 @@ module Promoted | |
| 120 149 | 
             
                        insertion_obj                = Hash[insertion_obj]
         | 
| 121 150 | 
             
                        insertion_obj[:user_info]    = user_info
         | 
| 122 151 | 
             
                        insertion_obj[:timing]       = timing
         | 
| 123 | 
            -
                        insertion_obj[:insertion_id] =  | 
| 152 | 
            +
                        insertion_obj[:insertion_id] = @id_generator.newID
         | 
| 124 153 | 
             
                        insertion_obj[:request_id]   = request_id
         | 
| 125 154 | 
             
                        insertion_obj[:position]     = offset + index
         | 
| 126 155 | 
             
                        insertion_obj                = @to_compact_metrics_insertion_func.call(insertion_obj) if @to_compact_metrics_insertion_func
         | 
| @@ -131,6 +160,14 @@ module Promoted | |
| 131 160 |  | 
| 132 161 | 
             
                    private
         | 
| 133 162 |  | 
| 163 | 
            +
                    def add_missing_ids_on_insertions! request, insertions
         | 
| 164 | 
            +
                      insertions.each do |insertion|
         | 
| 165 | 
            +
                        insertion[:insertion_id] = @id_generator.newID if not insertion[:insertion_id]
         | 
| 166 | 
            +
                        insertion[:session_id] = request[:session_id] if request[:session_id]
         | 
| 167 | 
            +
                        insertion[:request_id] = request[:request_id] if request[:request_id]
         | 
| 168 | 
            +
                      end
         | 
| 169 | 
            +
                    end
         | 
| 170 | 
            +
             | 
| 134 171 | 
             
                    # A list of the response Insertions.  This client expects lists to be truncated
         | 
| 135 172 | 
             
                    # already to request.paging.size.  If not truncated, this client will truncate
         | 
| 136 173 | 
             
                    # the list.
         | 
| @@ -142,6 +179,6 @@ module Promoted | |
| 142 179 | 
             
              end
         | 
| 143 180 | 
             
            end
         | 
| 144 181 |  | 
| 145 | 
            -
            require 'securerandom'
         | 
| 146 182 | 
             
            require "promoted/ruby/client/constants"
         | 
| 147 183 | 
             
            require "promoted/ruby/client/extensions"
         | 
| 184 | 
            +
            require "promoted/ruby/client/id_generator"
         | 
    
        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. | 
| 4 | 
            +
              version: 0.1.9
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - scottmcmaster
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2021-07- | 
| 11 | 
            +
            date: 2021-07-23 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -75,6 +75,8 @@ files: | |
| 75 75 | 
             
            - lib/promoted/ruby/client/errors.rb
         | 
| 76 76 | 
             
            - lib/promoted/ruby/client/extensions.rb
         | 
| 77 77 | 
             
            - lib/promoted/ruby/client/faraday_http_client.rb
         | 
| 78 | 
            +
            - lib/promoted/ruby/client/id_generator.rb
         | 
| 79 | 
            +
            - lib/promoted/ruby/client/pager.rb
         | 
| 78 80 | 
             
            - lib/promoted/ruby/client/request_builder.rb
         | 
| 79 81 | 
             
            - lib/promoted/ruby/client/sampler.rb
         | 
| 80 82 | 
             
            - lib/promoted/ruby/client/util.rb
         |