Class: Files::ApiClient

Inherits:
Object
  • Object
show all
Defined in:
lib/files.com/api_client.rb

Defined Under Namespace

Classes: RequestLogContext

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(conn = nil) ⇒ ApiClient

Returns a new instance of ApiClient.



7
8
9
10
11
# File 'lib/files.com/api_client.rb', line 7

def initialize(conn = nil)
  self.conn = conn || self.class.default_conn
  @system_profiler = SystemProfiler.new
  @last_request_metrics = nil
end

Instance Attribute Details

#connObject

Returns the value of attribute conn.



5
6
7
# File 'lib/files.com/api_client.rb', line 5

def conn
  @conn
end

Class Method Details

.active_clientObject



13
14
15
# File 'lib/files.com/api_client.rb', line 13

def self.active_client
  Thread.current[:files_api_client] || default_client
end

.build_default_conn(force_net_http: false) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/files.com/api_client.rb', line 35

def self.build_default_conn(force_net_http: false)
  conn = Faraday.new do |builder|
    builder.use Faraday::Request::Multipart
    builder.use Faraday::Request::UrlEncoded
    builder.use Faraday::Response::RaiseError

    if Gem.win_platform? || RUBY_PLATFORM == "java" || force_net_http
      builder.adapter :net_http
    else
      builder.adapter :net_http_persistent
    end
  end

  conn.proxy = Files.proxy if Files.proxy
  conn.ssl.verify = true

  conn
end

.default_clientObject



27
28
29
# File 'lib/files.com/api_client.rb', line 27

def self.default_client
  Thread.current[:files_api_client_default_client] ||= ApiClient.new(default_conn)
end

.default_connObject



31
32
33
# File 'lib/files.com/api_client.rb', line 31

def self.default_conn
  Thread.current[:files_api_client_default_conn] ||= build_default_conn
end

.download_clientObject

net_http_persistent does not support streaming downloads with faraday when directly downloading from S3 falling back to net_http.



19
20
21
# File 'lib/files.com/api_client.rb', line 19

def self.download_client
  Thread.current[:files_api_client_download_client] ||= ApiClient.new(download_conn)
end

.download_connObject



23
24
25
# File 'lib/files.com/api_client.rb', line 23

def self.download_conn
  Thread.current[:files_api_client_download_conn] ||= build_default_conn(force_net_http: true)
end

.should_retry?(error, num_retries) ⇒ Boolean

Returns:

  • (Boolean)


54
55
56
57
58
59
60
61
# File 'lib/files.com/api_client.rb', line 54

def self.should_retry?(error, num_retries)
  return false if num_retries >= Files.max_network_retries
  return true if error.is_a?(Faraday::TimeoutError)
  return true if error.is_a?(Faraday::ConnectionFailed)
  return true if error.is_a?(Faraday::ServerError)

  false
end

.sleep_time(num_retries) ⇒ Object



63
64
65
66
67
68
69
70
# File 'lib/files.com/api_client.rb', line 63

def self.sleep_time(num_retries)
  sleep_seconds = [
    Files.initial_network_retry_delay * (2**(num_retries - 1)),
    Files.max_network_retry_delay
  ].min
  sleep_seconds *= (0.5 * (1 + rand))
  [ Files.initial_network_retry_delay, sleep_seconds ].max
end

Instance Method Details

#cursorObject



167
168
169
# File 'lib/files.com/api_client.rb', line 167

def cursor
  @last_response.http_headers["x-files-cursor"]
end

#execute_request(method, path, base_url: nil, api_key: nil, session_id: nil, headers: {}, params: {}) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/files.com/api_client.rb', line 85

def execute_request(method, path, base_url: nil, api_key: nil, session_id: nil, headers: {}, params: {})
  base_url ||= Files.base_url
  session_id ||= Files.session_id

  if session_id and session_id != ""
    check_session_id!(session_id)
  elsif path !~ /^\/sessions/ # TODO: automate this to refer to any unauthenticated endpoint
    api_key ||= Files.api_key
    check_api_key!(api_key)
  end

  body = nil
  query_params = nil
  case method.to_s.downcase.to_sym
  when :get, :head, :delete
    query_params = params
  else
    body = params
  end

  headers = request_headers(api_key, session_id, method).update(headers)
  url = api_url(path, base_url)

  context = RequestLogContext.new
  context.api_key      = api_key
  context.body         = body
  context.method       = method
  context.path         = path
  context.query_params = query_params if query_params
  context.session_id   = session_id

  http_resp = execute_request_with_rescues(base_url, context) do
    conn.run_request(method, url, body, headers) do |req|
      req.options.open_timeout = Files.open_timeout
      req.options.timeout = Files.read_timeout
      req.params = query_params unless query_params.nil?
    end
  end

  begin
    resp = Response.from_faraday_response(http_resp)
  rescue JSON::ParserError
    raise general_api_error(http_resp.status, http_resp.body)
  end

  @last_response = resp
  [ resp, api_key, session_id ]
end

#execute_request_with_rescues(base_url, context, skip_body_logging = false) ⇒ Object



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/files.com/api_client.rb', line 193

def execute_request_with_rescues(base_url, context, skip_body_logging = false)
  num_retries = 0
  begin
    request_start = Time.now
    log_request(context, num_retries, skip_body_logging)
    resp = yield
    log_response(context, request_start, resp.status, resp.body, skip_body_logging)
  rescue StandardError => e
    error_context = context

    if e.respond_to?(:response) && e.response
      error_context = context
      log_response(error_context, request_start,
                   e.response[:status], e.response[:body], skip_body_logging
      )
    else
      log_response_error(error_context, request_start, e)
    end

    if self.class.should_retry?(e, num_retries)
      num_retries += 1
      sleep self.class.sleep_time(num_retries)
      retry
    end

    case e
    when Faraday::ClientError
      if e.response
        handle_error_response(e.response, error_context)
      else
        handle_network_error(e, error_context, num_retries, base_url)
      end

    else
      raise
    end
  end

  resp
end

#remote_request(method, url, headers = {}, body = nil) ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/files.com/api_client.rb', line 134

def remote_request(method, url, headers = {}, body = nil)
  context = RequestLogContext.new
  context.method       = method
  context.path         = url

  execute_request_with_rescues(Files.base_url, context, true) do
    conn.run_request(method, url, body, headers) do |req|
      req.options.open_timeout = Files.open_timeout
      req.options.timeout = Files.read_timeout
      yield(req) if block_given?
    end
  end
end

#requestObject



72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/files.com/api_client.rb', line 72

def request
  @last_response = nil
  old_files_api_client = Thread.current[:files_api_client]
  Thread.current[:files_api_client] = self

  begin
    res = yield
    [ res, @last_response ]
  ensure
    Thread.current[:files_api_client] = old_files_api_client
  end
end

#stream_download(uri, io) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/files.com/api_client.rb', line 148

def stream_download(uri, io)
  if conn.adapter == Faraday::Adapter::NetHttp
    uri = URI(uri)
    Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
      request = Net::HTTP::Get.new uri
      http.request request do |response|
        io.fulfill_content_length(response.content_length) if io.respond_to?(:fulfill_content_length)
        response.read_body do |chunk|
          io << chunk.encode!
        end
      end
    end
  else
    response = remote_request(:get, uri)
    io.fulfill_content_length(response.content_length) if io.respond_to?(:fulfill_content_length)
    io.write(response.body)
  end
end