<commit_before>require 'typhoeus'
require 'json'

# TODO: add some intelligent way of using the bulk endpoints...

module Bandiera
  class Client
    class RequestError < StandardError; end
    class ServerDownError < StandardError; end
    class TimeOutError < StandardError; end

    HANDLED_EXCEPTIONS = [RequestError, ServerDownError, TimeOutError]

    attr_accessor :timeout
    attr_reader :logger

    def initialize(base_uri = 'http://localhost', logger = Logger.new($stdout), client_name = nil)
      @base_uri    = base_uri
      @logger      = logger
      @timeout     = 0.02 # 20ms default timeout
      @client_name = client_name

      @base_uri << '/api' unless @base_uri.match(/\/api$/)
    end

    def enabled?(group, feature, params = { user_group: nil })
      get_feature(group, feature, params)
    end

    private

    def headers
      headers = {
        'User-Agent' => "Bandiera Ruby Client / #{Bandiera::Client::VERSION}"
      }
      headers.merge! 'Bandiera-Client' => @client_name unless @client_name.nil?
      headers
    end

    def get_feature(group, feature, params)
      path             = "/v2/groups/#{group}/features/#{feature}"
      default_response = false
      error_msg_prefix = "[Bandiera::Client#get_feature] '#{group} / #{feature} / #{params}'"

      get_and_handle_exceptions(path, params, default_response, error_msg_prefix)
    end

    def get_features_for_group(group, params)
      path             = "/v2/groups/#{group}/features"
      default_response = {}
      error_msg_prefix = "[Bandiera::Client#get_features_for_group] '#{group} / #{params}'"

      get_and_handle_exceptions(path, params, default_response, error_msg_prefix)
    end

    def get_all(params)
      path             = '/v2/all'
      default_response = {}
      error_msg_prefix = "[Bandiera::Client#get_all] '#{params}'"

      get_and_handle_exceptions(path, params, default_response, error_msg_prefix)
    end

    def get_and_handle_exceptions(path, params, return_upon_error, error_msg_prefix)
      res = get(path, params)
      logger.warn "#{error_msg_prefix} - #{res['warning']}" if res['warning']
      res['response']
    rescue *HANDLED_EXCEPTIONS => error
      logger.warn("#{error_msg_prefix} - #{error.message}")
      return_upon_error
    end

    def get(path, params)
      url     = "#{@base_uri}#{path}"
      request = Typhoeus::Request.new(
        url,
        method:         :get,
        timeout:        timeout,
        connecttimeout: timeout,
        params:         clean_params(params),
        headers:        headers
      )

      request.on_complete do |response|
        if response.success?
          # w00t
        elsif response.timed_out?
          fail TimeOutError, "Timeout occured requesting '#{url}'"
        elsif response.code == 0
          fail ServerDownError, 'Bandiera appears to be down.'
        else
          fail RequestError, "GET request to '#{url}' returned #{response.code}"
        end
      end

      JSON.parse(request.run.body)
    end

    def clean_params(passed_params)
      params = {}
<commit_msg>Logging<commit_after>require 'typhoeus'
require 'json'

# TODO: add some intelligent way of using the bulk endpoints...

module Bandiera
  class Client
    class RequestError < StandardError; end
    class ServerDownError < StandardError; end
    class TimeOutError < StandardError; end

    HANDLED_EXCEPTIONS = [RequestError, ServerDownError, TimeOutError]

    attr_accessor :timeout
    attr_reader :logger

    def initialize(base_uri = 'http://localhost', logger = Logger.new($stdout), client_name = nil)
      @base_uri    = base_uri
      @logger      = logger
      @timeout     = 0.02 # 20ms default timeout
      @client_name = client_name

      @base_uri << '/api' unless @base_uri.match(/\/api$/)
    end

    def enabled?(group, feature, params = { user_group: nil })
      get_feature(group, feature, params)
    end

    private

    def headers
      headers = {
        'User-Agent' => "Bandiera Ruby Client / #{Bandiera::Client::VERSION}"
      }
      headers.merge! 'Bandiera-Client' => @client_name unless @client_name.nil?
      headers
    end

    def get_feature(group, feature, params)
      path             = "/v2/groups/#{group}/features/#{feature}"
      default_response = false
      error_msg_prefix = "[Bandiera::Client#get_feature] '#{group} / #{feature} / #{params}'"

      get_and_handle_exceptions(path, params, default_response, error_msg_prefix)
    end

    def get_features_for_group(group, params)
      path             = "/v2/groups/#{group}/features"
      default_response = {}
      error_msg_prefix = "[Bandiera::Client#get_features_for_group] '#{group} / #{params}'"

      get_and_handle_exceptions(path, params, default_response, error_msg_prefix)
    end

    def get_all(params)
      path             = '/v2/all'
      default_response = {}
      error_msg_prefix = "[Bandiera::Client#get_all] '#{params}'"

      get_and_handle_exceptions(path, params, default_response, error_msg_prefix)
    end

    def get_and_handle_exceptions(path, params, return_upon_error, error_msg_prefix)
      res = get(path, params)
      logger.warn "#{error_msg_prefix} - #{res['warning']}" if res['warning']
      res['response']
    rescue *HANDLED_EXCEPTIONS => error
      logger.warn("#{error_msg_prefix} - #{error.message}")
      return_upon_error
    end

    def get(path, params)
      url     = "#{@base_uri}#{path}"
      request = Typhoeus::Request.new(
        url,
        method:         :get,
        timeout:        timeout,
        connecttimeout: timeout,
        params:         clean_params(params),
        headers:        headers
      )

      request.on_complete do |response|
        if response.success?
          logger.debug "Request for '#{url}' succeeded. [cached = #{response.cached?}]"
        elsif response.timed_out?
          logger.warn "Request for '#{url}' timed out."
          fail TimeOutError, "Timeout occured requesting '#{url}'"
        elsif response.code == 0
          logger.warn "Bandiera appeared down when requesting '#{url}'"
          fail ServerDownError, 'Bandiera appears to be down.'
        else
          logger.warn "Bandiera returned '#{response.code}' when requesting '#{url}'"
          fail RequestError, "GET request to '#{url}' returned #{response.code}"
        end
      end

      logger.debug "I will request #{path} with params #{params.inspect}"
      JSON.parse(request.run.body)
    end

    def clean_params(passed_params)
      params = {}

{'fraction_non_alphanumeric': 0.11310701781093013, 'fraction_numerical': 0.0030446034404018876, 'mean_word_length': 2.6848008973639934, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4402749', 'n_tokens_mistral': 1984, 'n_tokens_neox': 1921, 'n_words': 458}