class Acme::Client::FaradayMiddleware

def call(env)

def call(env)
  @env = env
  @env.body = crypto.generate_signed_jws(header: { nonce: pop_nonce }, payload: env.body)
  @app.call(env).on_complete { |response_env| on_complete(response_env) }
rescue Faraday::TimeoutError
  raise Acme::Client::Error::Timeout
end

def crypto

def crypto
  @crypto ||= Acme::Client::Crypto.new(private_key)
end

def decode_body

def decode_body
  content_type = env.response_headers['Content-Type']
  if content_type == 'application/json' || content_type == 'application/problem+json'
    JSON.load(env.body)
  else
    env.body
  end
end

def decode_link_headers

def decode_link_headers
  return unless env.response_headers.key?('Link')
  link_header = env.response_headers['Link']
  links = link_header.split(', ').map { |entry|
    _, link, name = *entry.match(LINK_MATCH)
    [name, link]
  }
  Hash[*links.flatten]
end

def error_class

def error_class
  if error_name.present? && Acme::Client::Error.qualified_const_defined?(error_name)
    "Acme::Client::Error::#{error_name}".constantize
  else
    Acme::Client::Error
  end
end

def error_message

def error_message
  if env.body.is_a? Hash
    env.body['detail']
  else
    "Error message: #{env.body}"
  end
end

def error_name

def error_name
  @error_name ||= begin
    return unless env.present? && env.body.present? && env.body.key?('type')
    env.body['type'].gsub('urn:acme:error:', '').classify
  end
end

def get_nonce

def get_nonce
  response = Faraday.head(env.url)
  response.headers['replay-nonce']
end

def initialize(app, client:)

def initialize(app, client:)
  super(app)
  @client = client
end

def nonces

def nonces
  client.nonces
end

def on_complete(env)

def on_complete(env)
  @env = env
  raise_on_not_found!
  store_nonce
  env.body = decode_body
  env.response_headers['Link'] = decode_link_headers
  return if env.success?
  raise_on_error!
end

def pop_nonce

def pop_nonce
  if nonces.empty?
    get_nonce
  else
    nonces.pop
  end
end

def private_key

def private_key
  client.private_key
end

def raise_on_error!

def raise_on_error!
  raise error_class, error_message
end

def raise_on_not_found!

def raise_on_not_found!
  raise Acme::Client::Error::NotFound, env.url.to_s if env.status == 404
end

def store_nonce

def store_nonce
  nonces << env.response_headers['replay-nonce']
end