smartsheet 1.0.0.beta.0
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 +7 -0
- data/.gitignore +10 -0
- data/.rubocop.yml +5 -0
- data/.travis.yml +6 -0
- data/Gemfile +6 -0
- data/LICENSE +202 -0
- data/README.md +139 -0
- data/Rakefile +13 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/smartsheet.rb +3 -0
- data/lib/smartsheet/api/body_builder.rb +26 -0
- data/lib/smartsheet/api/endpoint_spec.rb +35 -0
- data/lib/smartsheet/api/faraday_adapter/faraday_net_client.rb +42 -0
- data/lib/smartsheet/api/faraday_adapter/faraday_response.rb +60 -0
- data/lib/smartsheet/api/faraday_adapter/middleware/faraday_error_translator.rb +20 -0
- data/lib/smartsheet/api/faraday_adapter/middleware/response_parser.rb +25 -0
- data/lib/smartsheet/api/file_spec.rb +28 -0
- data/lib/smartsheet/api/header_builder.rb +85 -0
- data/lib/smartsheet/api/request.rb +29 -0
- data/lib/smartsheet/api/request_client.rb +26 -0
- data/lib/smartsheet/api/request_logger.rb +148 -0
- data/lib/smartsheet/api/request_spec.rb +43 -0
- data/lib/smartsheet/api/response_net_client_decorator.rb +47 -0
- data/lib/smartsheet/api/retry_logic.rb +37 -0
- data/lib/smartsheet/api/retry_net_client_decorator.rb +36 -0
- data/lib/smartsheet/api/url_builder.rb +25 -0
- data/lib/smartsheet/client.rb +115 -0
- data/lib/smartsheet/constants.rb +16 -0
- data/lib/smartsheet/endpoints/contacts/contacts.rb +29 -0
- data/lib/smartsheet/endpoints/favorites/favorites.rb +158 -0
- data/lib/smartsheet/endpoints/folders/folders.rb +124 -0
- data/lib/smartsheet/endpoints/groups/groups.rb +82 -0
- data/lib/smartsheet/endpoints/home/home.rb +19 -0
- data/lib/smartsheet/endpoints/reports/reports.rb +96 -0
- data/lib/smartsheet/endpoints/reports/reports_share.rb +68 -0
- data/lib/smartsheet/endpoints/search/search.rb +29 -0
- data/lib/smartsheet/endpoints/server_info/server_info.rb +19 -0
- data/lib/smartsheet/endpoints/share/share.rb +58 -0
- data/lib/smartsheet/endpoints/sheets/cells.rb +80 -0
- data/lib/smartsheet/endpoints/sheets/columns.rb +65 -0
- data/lib/smartsheet/endpoints/sheets/comments.rb +60 -0
- data/lib/smartsheet/endpoints/sheets/comments_attachments.rb +77 -0
- data/lib/smartsheet/endpoints/sheets/discussions.rb +80 -0
- data/lib/smartsheet/endpoints/sheets/discussions_attachments.rb +21 -0
- data/lib/smartsheet/endpoints/sheets/rows.rb +91 -0
- data/lib/smartsheet/endpoints/sheets/rows_attachments.rb +91 -0
- data/lib/smartsheet/endpoints/sheets/sheets.rb +301 -0
- data/lib/smartsheet/endpoints/sheets/sheets_attachments.rb +173 -0
- data/lib/smartsheet/endpoints/sheets/sheets_share.rb +68 -0
- data/lib/smartsheet/endpoints/sights/sights.rb +97 -0
- data/lib/smartsheet/endpoints/sights/sights_share.rb +68 -0
- data/lib/smartsheet/endpoints/templates/templates.rb +28 -0
- data/lib/smartsheet/endpoints/token/token.rb +57 -0
- data/lib/smartsheet/endpoints/update_requests/sent_update_requests.rb +42 -0
- data/lib/smartsheet/endpoints/update_requests/update_requests.rb +69 -0
- data/lib/smartsheet/endpoints/users/alternate_emails.rb +77 -0
- data/lib/smartsheet/endpoints/users/users.rb +73 -0
- data/lib/smartsheet/endpoints/webhooks/webhooks.rb +70 -0
- data/lib/smartsheet/endpoints/workspaces/workspaces.rb +83 -0
- data/lib/smartsheet/endpoints/workspaces/workspaces_share.rb +68 -0
- data/lib/smartsheet/error.rb +30 -0
- data/lib/smartsheet/general_request.rb +53 -0
- data/lib/smartsheet/version.rb +5 -0
- data/read-write-sheet/config.json +4 -0
- data/read-write-sheet/read_write_sheet.rb +89 -0
- data/smartsheet.gemspec +47 -0
- metadata +279 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'url_builder'
|
2
|
+
|
3
|
+
module Smartsheet
|
4
|
+
module API
|
5
|
+
class EndpointSpec
|
6
|
+
attr_reader :method, :url_segments, :spec
|
7
|
+
|
8
|
+
def initialize(method, url, **spec)
|
9
|
+
@method = method
|
10
|
+
@url_segments = url
|
11
|
+
@spec = spec
|
12
|
+
end
|
13
|
+
|
14
|
+
def requires_auth?
|
15
|
+
!spec.key?(:no_auth)
|
16
|
+
end
|
17
|
+
|
18
|
+
def requires_body?
|
19
|
+
spec.key? :body_type
|
20
|
+
end
|
21
|
+
|
22
|
+
def sending_file?
|
23
|
+
requires_body? && spec[:body_type] == :file
|
24
|
+
end
|
25
|
+
|
26
|
+
def sending_json?
|
27
|
+
requires_body? && spec[:body_type] == :json
|
28
|
+
end
|
29
|
+
|
30
|
+
def headers
|
31
|
+
spec.key?(:headers) ? spec[:headers] : {}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'smartsheet/api/request'
|
3
|
+
require 'smartsheet/api/faraday_adapter/middleware/faraday_error_translator'
|
4
|
+
require 'smartsheet/api/faraday_adapter/middleware/response_parser'
|
5
|
+
|
6
|
+
module Smartsheet
|
7
|
+
module API
|
8
|
+
class FaradayNetClient
|
9
|
+
def initialize
|
10
|
+
create_connection
|
11
|
+
end
|
12
|
+
|
13
|
+
# Expected output:
|
14
|
+
# - returned Success Response
|
15
|
+
# - returned Error Response
|
16
|
+
# - thrown Request Error
|
17
|
+
def make_request(request)
|
18
|
+
response = conn.send(request.method) do |req|
|
19
|
+
req.url(request.url)
|
20
|
+
req.headers = request.headers
|
21
|
+
req.params = request.params
|
22
|
+
req.body = request.body
|
23
|
+
end
|
24
|
+
|
25
|
+
response.body
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def create_connection
|
31
|
+
@conn = Faraday.new do |conn|
|
32
|
+
conn.use Middleware::FaradayErrorTranslator
|
33
|
+
conn.use Middleware::ResponseParser
|
34
|
+
|
35
|
+
conn.adapter Faraday.default_adapter
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_reader :conn
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Smartsheet
|
2
|
+
module API
|
3
|
+
class FaradayResponse
|
4
|
+
def self.from_response_env(faraday_response)
|
5
|
+
if faraday_response[:body].kind_of?(Hash) && faraday_response[:body].key?(:errorCode)
|
6
|
+
FaradayErrorResponse.new(faraday_response[:body], faraday_response)
|
7
|
+
else
|
8
|
+
FaradaySuccessResponse.new(faraday_response[:body], faraday_response)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :status_code, :reason_phrase, :headers
|
13
|
+
|
14
|
+
def initialize(faraday_response)
|
15
|
+
@status_code = faraday_response[:status]
|
16
|
+
@reason_phrase = faraday_response[:reason_phrase]
|
17
|
+
@headers = faraday_response[:response_headers]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class FaradayErrorResponse < FaradayResponse
|
22
|
+
RETRYABLE_ERRORS = 4001..4004
|
23
|
+
|
24
|
+
attr_reader :error_code, :message, :ref_id, :detail
|
25
|
+
|
26
|
+
def initialize(result, faraday_response)
|
27
|
+
super(faraday_response)
|
28
|
+
@error_code = result[:errorCode]
|
29
|
+
@message = result[:message]
|
30
|
+
@ref_id = result[:refId]
|
31
|
+
@detail = result[:detail]
|
32
|
+
end
|
33
|
+
|
34
|
+
def should_retry?
|
35
|
+
RETRYABLE_ERRORS.include? error_code
|
36
|
+
end
|
37
|
+
|
38
|
+
def success?
|
39
|
+
false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class FaradaySuccessResponse < FaradayResponse
|
44
|
+
attr_reader :result
|
45
|
+
|
46
|
+
def initialize(result, faraday_response)
|
47
|
+
super(faraday_response)
|
48
|
+
@result = result
|
49
|
+
end
|
50
|
+
|
51
|
+
def should_retry?
|
52
|
+
false
|
53
|
+
end
|
54
|
+
|
55
|
+
def success?
|
56
|
+
true
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'smartsheet/error'
|
3
|
+
|
4
|
+
module Smartsheet
|
5
|
+
module API
|
6
|
+
module Middleware
|
7
|
+
class FaradayErrorTranslator < Faraday::Middleware
|
8
|
+
def initialize(app)
|
9
|
+
super(app)
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
@app.call(env)
|
14
|
+
rescue Faraday::Error => e
|
15
|
+
raise Smartsheet::RequestError, e
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'json'
|
3
|
+
require 'smartsheet/api/faraday_adapter/faraday_response'
|
4
|
+
|
5
|
+
module Smartsheet
|
6
|
+
module API
|
7
|
+
module Middleware
|
8
|
+
class ResponseParser < Faraday::Middleware
|
9
|
+
def initialize(app)
|
10
|
+
super(app)
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
@app.call(env).on_complete do |response_env|
|
15
|
+
if response_env[:response_headers]['content-type'] =~ /\bjson\b/
|
16
|
+
response_env[:body] = JSON.parse(response_env[:body], symbolize_names: true)
|
17
|
+
end
|
18
|
+
|
19
|
+
response_env[:body] = FaradayResponse.from_response_env response_env
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'faraday'
|
3
|
+
|
4
|
+
module Smartsheet
|
5
|
+
module API
|
6
|
+
class PathFileSpec
|
7
|
+
attr_reader :upload_io, :filename, :content_type, :file_length
|
8
|
+
|
9
|
+
def initialize(path, filename, content_type)
|
10
|
+
@file_length = File.size(path)
|
11
|
+
@filename = filename.nil? ? File.basename(path) : filename
|
12
|
+
@upload_io = Faraday::UploadIO.new(path, content_type, CGI::escape(@filename))
|
13
|
+
@content_type = content_type
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class ObjectFileSpec
|
18
|
+
attr_reader :upload_io, :filename, :content_type, :file_length
|
19
|
+
|
20
|
+
def initialize(file, filename, file_length, content_type)
|
21
|
+
@file_length = file_length
|
22
|
+
@filename = filename
|
23
|
+
@upload_io = Faraday::UploadIO.new(file, content_type, CGI::escape(filename))
|
24
|
+
@content_type = content_type
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'smartsheet/version'
|
3
|
+
require 'smartsheet/constants'
|
4
|
+
|
5
|
+
module Smartsheet
|
6
|
+
module API
|
7
|
+
# Constructs headers for accessing the Smartsheet API
|
8
|
+
class HeaderBuilder
|
9
|
+
include Smartsheet::Constants
|
10
|
+
def initialize(token, endpoint_spec, request_spec, assume_user: nil)
|
11
|
+
@token = token
|
12
|
+
@endpoint_spec = endpoint_spec
|
13
|
+
@request_spec = request_spec
|
14
|
+
@assume_user = assume_user
|
15
|
+
end
|
16
|
+
|
17
|
+
def build
|
18
|
+
base_headers
|
19
|
+
.merge(endpoint_headers)
|
20
|
+
.merge(content_type)
|
21
|
+
.merge(content_disposition)
|
22
|
+
.merge(content_length)
|
23
|
+
.merge(request_headers)
|
24
|
+
.merge(assume_user)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_accessor :endpoint_spec, :request_spec
|
30
|
+
attr_reader :token
|
31
|
+
|
32
|
+
def base_headers
|
33
|
+
base = {
|
34
|
+
Accept: JSON_TYPE,
|
35
|
+
'User-Agent': "#{USER_AGENT}/#{Smartsheet::VERSION}"
|
36
|
+
}
|
37
|
+
base[:Authorization] = "Bearer #{token}" if endpoint_spec.requires_auth?
|
38
|
+
|
39
|
+
base
|
40
|
+
end
|
41
|
+
|
42
|
+
def assume_user
|
43
|
+
if @assume_user.nil?
|
44
|
+
{}
|
45
|
+
else
|
46
|
+
{'Assume-User': CGI::escape(@assume_user)}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def endpoint_headers
|
51
|
+
endpoint_spec.headers
|
52
|
+
end
|
53
|
+
|
54
|
+
def content_type
|
55
|
+
if endpoint_spec.sending_json? && request_spec.body
|
56
|
+
{'Content-Type': JSON_TYPE}
|
57
|
+
elsif endpoint_spec.sending_file?
|
58
|
+
{'Content-Type': request_spec.content_type}
|
59
|
+
else
|
60
|
+
{}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def content_disposition
|
65
|
+
if endpoint_spec.sending_file?
|
66
|
+
{'Content-Disposition': "attachment; filename=\"#{CGI::escape(request_spec.filename)}\""}
|
67
|
+
else
|
68
|
+
{}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def content_length
|
73
|
+
if endpoint_spec.sending_file?
|
74
|
+
{'Content-Length': request_spec.file_length.to_s}
|
75
|
+
else
|
76
|
+
{}
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def request_headers
|
81
|
+
request_spec.header_overrides
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'smartsheet/api/url_builder'
|
2
|
+
require 'smartsheet/api/header_builder'
|
3
|
+
require 'smartsheet/api/body_builder'
|
4
|
+
|
5
|
+
module Smartsheet
|
6
|
+
module API
|
7
|
+
class Request
|
8
|
+
attr_reader :method, :url, :headers, :params, :body
|
9
|
+
|
10
|
+
def initialize(token, endpoint_spec, request_spec, base_url, assume_user: nil)
|
11
|
+
@method = endpoint_spec.method
|
12
|
+
@url = Smartsheet::API::UrlBuilder.new(endpoint_spec, request_spec, base_url).build
|
13
|
+
@headers = Smartsheet::API::HeaderBuilder.new(token, endpoint_spec, request_spec, assume_user: assume_user).build
|
14
|
+
@params = request_spec.params
|
15
|
+
@body = Smartsheet::API::BodyBuilder.new(endpoint_spec, request_spec).build
|
16
|
+
end
|
17
|
+
|
18
|
+
def ==(other)
|
19
|
+
other.class == self.class && other.equality_state == equality_state
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def equality_state
|
25
|
+
[method, url, headers, params, body]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'smartsheet/error'
|
2
|
+
|
3
|
+
module Smartsheet
|
4
|
+
module API
|
5
|
+
class RequestClient
|
6
|
+
def initialize(token, client, base_url, assume_user: nil, logger: MuteRequestLogger.new)
|
7
|
+
@token = token
|
8
|
+
@client = client
|
9
|
+
@assume_user = assume_user
|
10
|
+
@logger = logger
|
11
|
+
@base_url = base_url
|
12
|
+
end
|
13
|
+
|
14
|
+
def make_request(endpoint_spec, request_spec)
|
15
|
+
request = Request.new(token, endpoint_spec, request_spec, base_url, assume_user: assume_user)
|
16
|
+
|
17
|
+
logger.log_request(request)
|
18
|
+
client.make_request(request)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :token, :client, :assume_user, :logger, :base_url
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Smartsheet
|
4
|
+
module API
|
5
|
+
class Censor
|
6
|
+
EXPOSED_CHARS = 4
|
7
|
+
|
8
|
+
def initialize(*blacklist)
|
9
|
+
@blacklist = Set.new(blacklist)
|
10
|
+
end
|
11
|
+
|
12
|
+
def censor_hash(h)
|
13
|
+
h.collect do |(k, v)|
|
14
|
+
new_v = blacklist.include?(k.to_s) ? censor(v) : v
|
15
|
+
[k, new_v]
|
16
|
+
end.to_h
|
17
|
+
end
|
18
|
+
|
19
|
+
def censor(str)
|
20
|
+
total_length = str.length
|
21
|
+
censored_length = [total_length - EXPOSED_CHARS, 0].max
|
22
|
+
('*' * censored_length) + str[censored_length...total_length]
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :blacklist
|
28
|
+
end
|
29
|
+
|
30
|
+
class RequestLogger
|
31
|
+
QUERY_PARAM_CENSOR = Censor.new 'code', 'client_id', 'hash', 'refresh_token'
|
32
|
+
HEADER_CENSOR = Censor.new 'authorization'
|
33
|
+
PAYLOAD_CENSOR = Censor.new 'access_token', 'refresh_token'
|
34
|
+
|
35
|
+
TRUNCATED_BODY_LENGTH = 1024
|
36
|
+
|
37
|
+
def initialize(logger, log_full_body:)
|
38
|
+
@logger = logger
|
39
|
+
@log_full_body = log_full_body
|
40
|
+
end
|
41
|
+
|
42
|
+
def log_request(request)
|
43
|
+
log_request_basics(Logger::INFO, request)
|
44
|
+
log_headers('Request', request)
|
45
|
+
log_body('Request', request.body)
|
46
|
+
end
|
47
|
+
|
48
|
+
def log_retry_attempt(request, response, attempt_num)
|
49
|
+
logger.warn { "Request attempt #{attempt_num} failed" }
|
50
|
+
log_request_basics(Logger::WARN, request)
|
51
|
+
log_api_error(Logger::WARN, response)
|
52
|
+
end
|
53
|
+
|
54
|
+
def log_retry_failure(num_tries)
|
55
|
+
try_word = num_tries == 1 ? 'try' : 'tries'
|
56
|
+
logger.error { "Request failed after #{num_tries} #{try_word}" }
|
57
|
+
end
|
58
|
+
|
59
|
+
def log_successful_response(response)
|
60
|
+
log_status(Logger::INFO, response)
|
61
|
+
log_headers('Response', response)
|
62
|
+
log_body('Response', response.result)
|
63
|
+
end
|
64
|
+
|
65
|
+
def log_error_response(request, error)
|
66
|
+
log_request_basics(Logger::ERROR, request)
|
67
|
+
log_api_error(Logger::ERROR, error)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
attr_reader :logger, :log_full_body
|
73
|
+
|
74
|
+
def log_request_basics(level, request)
|
75
|
+
logger.log(level) { "Request: #{request.method} #{build_logging_url(request)}" }
|
76
|
+
end
|
77
|
+
|
78
|
+
def build_logging_url(request)
|
79
|
+
query_params = QUERY_PARAM_CENSOR.censor_hash(request.params)
|
80
|
+
query_param_str =
|
81
|
+
if query_params.empty?
|
82
|
+
''
|
83
|
+
else
|
84
|
+
'?' + query_params.collect { |(k, v)| "#{k}=#{v}" }.join('&') # TODO: URI Encoding
|
85
|
+
end
|
86
|
+
request.url + query_param_str
|
87
|
+
end
|
88
|
+
|
89
|
+
def log_api_error(level, response)
|
90
|
+
log_status(level, response)
|
91
|
+
logger.log(level) do
|
92
|
+
"#{response.error_code}: #{response.message} - Ref ID: #{response.ref_id}"
|
93
|
+
end
|
94
|
+
log_headers('Response', response)
|
95
|
+
end
|
96
|
+
|
97
|
+
def log_status(level, response)
|
98
|
+
logger.log(level) { "Response: #{response.status_code} #{response.reason_phrase}" }
|
99
|
+
end
|
100
|
+
|
101
|
+
def log_headers(context, req_or_resp)
|
102
|
+
logger.debug { "#{context} Headers: #{HEADER_CENSOR.censor_hash(req_or_resp.headers)}" }
|
103
|
+
end
|
104
|
+
|
105
|
+
def log_body(context, body)
|
106
|
+
return unless body
|
107
|
+
|
108
|
+
body_str =
|
109
|
+
if body.is_a? String
|
110
|
+
body
|
111
|
+
elsif body.is_a? Hash
|
112
|
+
PAYLOAD_CENSOR.censor_hash(body).to_s
|
113
|
+
else
|
114
|
+
'<Binary body>'
|
115
|
+
end
|
116
|
+
|
117
|
+
body_str = truncate_body(body_str) unless log_full_body
|
118
|
+
|
119
|
+
logger.debug "#{context} Body: #{body_str}"
|
120
|
+
end
|
121
|
+
|
122
|
+
def truncate_body(body_str)
|
123
|
+
if body_str.length > TRUNCATED_BODY_LENGTH
|
124
|
+
body_str[0...TRUNCATED_BODY_LENGTH] + '...'
|
125
|
+
else
|
126
|
+
body_str
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class MuteRequestLogger
|
132
|
+
def log_request(request)
|
133
|
+
end
|
134
|
+
|
135
|
+
def log_retry_attempt(request, response, attempt_num)
|
136
|
+
end
|
137
|
+
|
138
|
+
def log_retry_failure(num_retries)
|
139
|
+
end
|
140
|
+
|
141
|
+
def log_successful_response(response)
|
142
|
+
end
|
143
|
+
|
144
|
+
def log_error_response(request, error)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|