lib/splitclient-rb/engine/api/segments.rb



# frozen_string_literal: true

module SplitIoClient
  module Api
    # Retrieves segment changes from the Split Backend
    class Segments < Client
      def initialize(api_key, segments_repository, config, telemetry_runtime_producer)
        super(config)
        @api_key = api_key
        @segments_repository = segments_repository
        @telemetry_runtime_producer = telemetry_runtime_producer
      end

      def fetch_segments_by_names(names, fetch_options = { cache_control_headers: false, till: nil })
        return if names.nil? || names.empty?

        names.each do |name|
          since = @segments_repository.get_change_number(name)

          loop do
            segment = fetch_segment_changes(name, since, fetch_options)
            @segments_repository.add_to_segment(segment)

            @config.split_logger.log_if_debug("Segment #{name} fetched before: #{since}, \
              till: #{@segments_repository.get_change_number(name)}")

            break if since.to_i >= @segments_repository.get_change_number(name).to_i

            since = @segments_repository.get_change_number(name)
          end
        end
      end

      private

      def fetch_segment_changes(name, since, fetch_options = { cache_control_headers: false, till: nil })
        start = Time.now

        params = { since: since }
        params[:till] = fetch_options[:till] unless fetch_options[:till].nil?
        response = get_api("#{@config.base_uri}/segmentChanges/#{name}", @api_key, params, fetch_options[:cache_control_headers])

        if response.success?
          segment = JSON.parse(response.body, symbolize_names: true)
          @segments_repository.set_change_number(name, segment[:till])

          @config.split_logger.log_if_debug("\'#{segment[:name]}\' segment retrieved.")
          unless segment[:added].empty?
            @config.split_logger.log_if_debug("\'#{segment[:name]}\' #{segment[:added].size} added keys")
          end
          unless segment[:removed].empty?
            @config.split_logger.log_if_debug("\'#{segment[:name]}\' #{segment[:removed].size} removed keys")
          end
          @config.split_logger.log_if_transport("Segment changes response: #{segment.to_s}")

          bucket = BinarySearchLatencyTracker.get_bucket((Time.now - start) * 1000.0)
          @telemetry_runtime_producer.record_sync_latency(Telemetry::Domain::Constants::SEGMENT_SYNC, bucket)
          @telemetry_runtime_producer.record_successful_sync(Telemetry::Domain::Constants::SEGMENT_SYNC, (Time.now.to_f * 1000.0).to_i)

          segment
        elsif response.status == 403
          @telemetry_runtime_producer.record_sync_error(Telemetry::Domain::Constants::SEGMENT_SYNC, response.status)

          @config.logger.error('Factory Instantiation: You passed a browser type api_key, ' \
            'please grab an api key from the Split console that is of type sdk')
          @config.valid_mode =  false
        else
          @telemetry_runtime_producer.record_sync_error(Telemetry::Domain::Constants::SEGMENT_SYNC, response.status)

          @config.logger.error("Unexpected status code while fetching segments: #{response.status}." \
          "Since #{since} - Check your API key and base URI")

          raise 'Split SDK failed to connect to backend to fetch segments'
        end
      end
    end
  end
end