class Dag::Client::API

Attributes

headers[RW]
analysis_api[R]
apikey[R]
storage_api[R]

Public Class Methods

new(apikey, secret, analysis_api: Dag::Settings.analysis_api, storage_api: Dag::Settings.storage_api, force_path_style: Dag::Settings.force_path_style, debug: Dag::Settings.debug) click to toggle source
# File lib/dag/client/api.rb, line 15
def initialize(apikey, secret,
               analysis_api: Dag::Settings.analysis_api,
               storage_api: Dag::Settings.storage_api,
               force_path_style: Dag::Settings.force_path_style,
               debug: Dag::Settings.debug)

  require 'time'
  require 'base64'
  require 'oj'
  require 'rexml/document'
  require 'erb'
  require 'net/http'
  require 'xmlsimple'
  require 'ipaddr'
  require 'httpclient'
  require 'stringio'

  @apikey = apikey
  @secret = secret

  unless [TrueClass, FalseClass].any? { |c| force_path_style.kind_of?(c) }
     raise Dag::Client::APIOptionInvalid.new("force_path_style is not boolean:#{force_path_style}")
  end

  unless [TrueClass, FalseClass].any? { |c| debug.kind_of?(c) }
    raise Dag::Client::APIOptionInvalid.new("debug is not boolean:#{debug}")
  end

  @analysis_api = analysis_api
  @storage_api = storage_api
  @force_path_style = force_path_style
  @debug = debug

  Oj.default_options = { mode: :compat }

  @http_client = HTTPClient.new
  @http_client.connect_timeout = 300
  @http_client.send_timeout    = 300
  @http_client.receive_timeout = 300
  @http_client.debug_dev = STDERR if @debug
end

Public Instance Methods

download_signature(expire_at, bucket, output_object) click to toggle source
# File lib/dag/client/api.rb, line 119
def download_signature(expire_at, bucket, output_object)
  http_verb = "GET\n"
  content_md5 = "\n"
  content_type = "\n"
  expire = "#{expire_at}\n"

  string_to_sign = http_verb + content_md5 + content_type + expire +
      canonicalized_resource(bucket, output_object)

  digest = OpenSSL::HMAC::digest(OpenSSL::Digest::SHA1.new, @secret, string_to_sign)
  Base64.encode64(digest).strip
end
execute(rest_parameter) click to toggle source
# File lib/dag/client/api.rb, line 63
def execute(rest_parameter)
  response = handle_api_failure(rest_parameter) do
    rest_client(:dag_gw, rest_parameter)
  end

  if response.present?
    STDERR.print "\n\n" if @debug

    if response.body == ''
      data = ''
    else
      data = Oj.load(response.body) || ''
    end
    
    data.instance_eval {
      class << self
        attr_accessor :headers
      end
    }
    data.headers = response.header
    return data.freeze
  end
end
execute_storage(rest_parameter, &block) click to toggle source
# File lib/dag/client/api.rb, line 87
def execute_storage(rest_parameter, &block)
  response = handle_api_failure(rest_parameter) do
    rest_client(:storage, rest_parameter, &block)
  end

  if response.present?
    data = if rest_parameter.raw_data?
             response.body
           else
             REXML::Document.new(response.body)
           end || ''

    if data.present?
      STDERR.print "\n\n" if @debug
    end

    data.instance_eval {
      class << self
        attr_accessor :headers
      end
    }
    data.headers = response.header
    return data.freeze
  end
end
force_path_style?() click to toggle source
# File lib/dag/client/api.rb, line 59
def force_path_style?
  @force_path_style
end

Private Instance Methods

canonicalized_resource(bucket, object) click to toggle source
# File lib/dag/client/api.rb, line 134
def canonicalized_resource(bucket, object)
  result = ''

  unless @force_path_style
    result = '/'
    result += "#{bucket}"
  end

  File.join(result, object)
end
handle_api_failure(rest_parameter, &block) click to toggle source
# File lib/dag/client/api.rb, line 145
def handle_api_failure(rest_parameter, &block)
  response = nil

  begin
    response = block.call

    unless response.try(:status).to_s =~ /^(2\d\d|3\d\d)$/
      raise Dag::Client::APIFailure
    end

    return response
  rescue Dag::Client::APIFailure
    msg = "api_failure #{rest_parameter}"
    api_failure = Dag::Client::APIFailure.new(msg)
    raise api_failure if response.blank?

    json_response = Oj.load(response.body) rescue nil
    if json_response
      api_failure.api_code = json_response['code']
      api_failure.api_message = json_response['message']
      api_failure.api_status = json_response['status']
      api_failure.api_request_id = json_response['requestId']
      api_failure.api_resource = json_response['resource']

    else
      begin
        xml_doc = REXML::Document.new(response.body)
        if xml_doc && xml_doc.elements['Error/Code']
          if xml_doc.elements['Error/Code']
            api_failure.api_code = xml_doc.elements['Error/Code'].text
          end
          if xml_doc.elements['Error/Message']
            api_failure.api_message = xml_doc.elements['Error/Message'].text
          end
          if xml_doc.elements['Error/Status']
            api_failure.api_status = xml_doc.elements['Error/Status'].text.to_i
          end
          if xml_doc.elements['Error/RequestId']
            api_failure.api_request_id = xml_doc.elements['Error/RequestId'].text
          end
          if xml_doc.elements['Error/Resource']
            api_failure.api_resource = xml_doc.elements['Error/Resource'].text
          end
        end
      rescue
        api_failure.api_code = nil
        api_failure.api_message = response.body
        api_failure.api_status = response.try(:status)
        api_failure.api_request_id = nil
        api_failure.api_resource = response.http_header.request_uri
      end
    end

    raise api_failure
  end

  response
end
host_name(kind, bucket) click to toggle source
# File lib/dag/client/api.rb, line 257
def host_name(kind, bucket)
  uri = host_uri(kind)
  result = uri.host

  if kind == :storage
    return result if valid_ip?(result)

    if !@force_path_style && bucket.present?
      result = "#{bucket}.#{result}"
    end
  end

  unless uri.port == 80 || uri.port == 443
    result += ":#{uri.port}"
  end

  result
end
host_uri(kind) click to toggle source
# File lib/dag/client/api.rb, line 285
def host_uri(kind)
  host_url = case kind
               when :dag_gw
                 @analysis_api
               when :storage
                 @storage_api
             end

  raise 'illegal kind' if host_url.blank?

  URI.parse(host_url)
end
rest_client(kind, rest_parameter, &block) click to toggle source
# File lib/dag/client/api.rb, line 204
def rest_client(kind, rest_parameter, &block)
  url = rest_parameter.url(host_uri(kind), @force_path_style)

  rest_parameter.headers.merge!({
    Authorization: rest_parameter.authentication(@apikey, @secret, @force_path_style),
    Date: rest_parameter.calc_date,
    Host: host_name(kind, rest_parameter.bucket),
    Accept: '*/*; q=0.5, application/xml',
    'Accept-Encoding' => 'gzip, deflate',
    'User-Agent' => "dag-client-ruby (#{Dag::Client::VERSION})"
  })

  parameters = rest_parameter.parameters

  unless rest_parameter.headers['Content-Type']
    if rest_parameter.content_type
      rest_parameter.headers.merge!(
          'Content-Type' => rest_parameter.content_type
      )
    end
  end

  payload = if parameters.present? || rest_parameter.blank_body?
              Oj.dump(parameters)
            elsif block_given?
              block.call
            end

  unless rest_parameter.headers['Content-Length']
    rest_parameter.headers.merge!(
        'Content-Length' => payload ? payload.size.to_s : 0.to_s
    )
  end

  STDERR.print "\n" if @debug

  headers = rest_parameter.headers
  case rest_parameter.method
    when :get
      @http_client.get(url, nil, headers)

    when :post
      @http_client.post(url, payload, headers)

    when :put
      @http_client.put(url, payload, headers)

    when :delete
      @http_client.delete(url, nil, headers)

  end
end
valid_ip?(str) click to toggle source
# File lib/dag/client/api.rb, line 276
def valid_ip?(str)
  begin
    IPAddr.new(str)
    true
  rescue
    false
  end
end