Class: E621ExportDownloader::Client

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/e621_export_downloader/client.rb,
lib/e621_export_downloader/client/options.rb,
lib/e621_export_downloader/client/options/builder.rb,
lib/e621_export_downloader/client/options/builder/parsers.rb

Defined Under Namespace

Classes: Options

Constant Summary collapse

Logger =
::Logger.new($stdout)
RETRYABLE_ERRORS =

transient network failures (DNS resolution, connection resets, timeouts, ...) worth retrying

T.let([Faraday::ConnectionFailed, Faraday::TimeoutError, Faraday::SSLError].freeze, T::Array[T.class_of(Faraday::Error)])

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = nil) ⇒ Client

Returns a new instance of Client.



21
22
23
24
# File 'lib/e621_export_downloader/client.rb', line 21

def initialize(options = nil)
  @options = T.let(options || Options.new, Options)
  @export_cache = T.let(nil, T.nilable(T::Array[APIExportData]))
end

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



18
19
20
# File 'lib/e621_export_downloader/client.rb', line 18

def options
  @options
end

Instance Method Details

#config(&block) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
# File 'lib/e621_export_downloader/client.rb', line 27

def config(&block)
  builder = Options::Builder.new(@options)
  block.call(builder)
  @options = Options.new(
    cache:             builder.cache,
    validate_checksum: builder.validate_checksum,
    parsers:           builder.parsers,
    retries:           builder.retries,
    retry_delay:       builder.retry_delay,
  )
end

#connectionObject



40
41
42
# File 'lib/e621_export_downloader/client.rb', line 40

def connection
  Faraday.new(headers: { "User-Agent" => Constants::USER_AGENT })
end

#debug(msg, header: []) ⇒ Object



45
46
47
# File 'lib/e621_export_downloader/client.rb', line 45

def debug(msg, header: [])
  Logger.debug("[e621_export_downloader#{":#{header.join(':')}" unless header.empty?}] #{msg}")
end

#get(type) ⇒ Object

Raises:



72
73
74
75
76
77
78
79
# File 'lib/e621_export_downloader/client.rb', line 72

def get(type)
  type = string_to_type(type) if type.is_a?(String)
  T.assert_type!(type, Types)
  data = get_data.find { |d| d.name == type }
  raise(ResolveError, "Export data for \"#{type.serialize}\" not found") if data.nil?
  debug("creating export for #{type.serialize}")
  Export.new(data: data, client: self, type: type, parser: options.parsers.public_send(type.serialize))
end

#get_dataObject

Raises:



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/e621_export_downloader/client.rb', line 90

def get_data
  return @export_cache unless @export_cache.nil?
  debug("fetching export data from api")
  res = with_retries(header: ["export_data"]) { connection.get(Constants::API_URL) }
  raise(ResolveError, "Failed to fetch exports: #{res.status} #{res.reason_phrase}") unless res.success?
  data = JSON.parse(T.unsafe(res).body)
  result = T.let(data.map do |d|
    APIExportData.new(
      name:       Types.deserialize(d["name"]),
      file_name:  d["file_name"],
      file_size:  d["file_size"].to_i,
      checksum:   d["checksum"],
      updated_at: d["updated_at"],
      url:        d["url"],
    )
  end, T::Array[APIExportData])
  @export_cache = result
end

#get_deferred(type) ⇒ Object



82
83
84
85
86
87
# File 'lib/e621_export_downloader/client.rb', line 82

def get_deferred(type)
  type = string_to_type(type) if type.is_a?(String)
  T.assert_type!(type, Types)
  debug("creating deferred export for #{type.serialize}")
  ExportHelper.new(type: type, client: self)
end

#with_retries(header: [], &block) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/e621_export_downloader/client.rb', line 56

def with_retries(header: [], &block)
  attempts = 0
  begin
    attempts += 1
    block.call
  rescue *RETRYABLE_ERRORS => e
    raise if attempts > options.retries
    delay = options.retry_delay * attempts
    debug("attempt #{attempts} failed (#{e.class}: #{e.message}), retrying in #{delay}s", header: header)
    ActiveSupport::Notifications.instrument("retry.e621_export_downloader", header: header, attempt: attempts, error: e.class.name, message: e.message, delay: delay)
    sleep(delay)
    retry
  end
end