# frozen_string_literal: true
class PriceApi
PRICEAPI_BASE_URL = "https://api.priceapi.com"
REFRESH_INTERVAL = 30.seconds
def self.token=(token)
Thread.current[:price_api_token] = token
end
def self.token
raise "Set PriceApi.token first!" if Thread.current[:price_api_token].nil?
return Thread.current[:price_api_token]
end
def self.bulk_request(source, country, key, values, completeness = "one_page", currentness = "daily_updated", retries = 3)
job_id, error = create_bulk_request(source, country, key, values, completeness, currentness, retries)
if job_id.nil?
puts "Failed to create bulk request: #{error}"
return nil
end
sleep REFRESH_INTERVAL until check_status(job_id, retries) == "finished"
json = download_results(job_id, retries)
return JSON.parse(json)
end
def self.create_bulk_request(source, country, key, values, completeness = "one_page", currentness = "daily_updated", _retries = 3)
values = [values] unless values.is_a?(Array)
raise "Too many values, max 1,000" if values.size > 1000
uri = URI("#{PRICEAPI_BASE_URL}/jobs")
form_data = {
token: token,
source: source,
country: country,
key: key,
values: values.join("\n"),
completeness: completeness,
currentness: currentness
}
body = send_post(uri, form_data)
response = JSON.parse(body)
puts "API response: #{response.inspect}"
if response["success"] == false
case response["reason"]
when "unauthorized"
puts "#{response["reason"]} - token is not valid"
when "missing parameter"
puts "#{response["reason"]} - not all required parameters were given"
when "parameter value invalid"
puts "#{response["reason"]} - given value is not allowed for this parameter"
when "unsupported source"
puts "#{response["reason"]} - chosen source is not supported (yet)"
when "unsupported country"
puts "#{response["reason"]} - chosen country is not supported for the chosen source"
when "unsupported key"
puts "#{response["reason"]} - chosen key is not supported by the chosen source"
when "not enough free credits"
puts "#{response["reason"]} - no free credits left, a paid subscription is needed"
when "daily quota exceeded"
puts "#{response["reason"]} - user defined daily quota is exceeded; you can change this under quota settings."
when "job not found"
puts "#{response["reason"]} - no bulk request could found for given job_id and token"
when "job not finished"
puts "#{response["reason"]} - bulk request is still in progress; wait until it is finished."
else
puts response["reason"]
end
return nil, response["reason"]
else
puts "Success. job_id: #{response["job_id"].inspect}"
return response["job_id"], nil
end
end
def self.check_status(job_id, retries = 3)
uri = URI("#{PRICEAPI_BASE_URL}/jobs/#{job_id}?token=#{token}")
body = send_get(uri, retries)
response = JSON.parse(body)
puts "API response: #{response.inspect}"
return response["status"]
end
def self.download_results(job_id, format = "json", retries = 3)
uri = URI("#{PRICEAPI_BASE_URL}/products/bulk/#{job_id}.#{format}?token=#{token}")
body = send_get(uri, retries)
response = JSON.parse(body)
puts "API response: #{response.inspect}"
return response["status"]
end
def self.send_post(uri, form_data, retries = 3)
puts "Send POST to #{uri}: #{form_data.inspect}"
try = 1
begin
req = Net::HTTP::Post.new(uri)
req.set_form_data(form_data)
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.read_timeout = 60
http.request(req)
end
puts "HTTP response: #{res.code}"
return res.body
rescue SystemCallError, Timeout::Error, Net::ProtocolError, IOError => e
puts "#{e.class.name}: #{e.message}"
retry if (try += 1) <= retries
raise e
end
end
def self.send_get(uri, _retries = 3)
puts "Send GET to #{uri}"
try = 1
begin
http = Net::HTTP.new(uri.hostname, uri.port)
http.use_ssl = true
http.read_timeout = 15 * 60
res = http.get(uri.request_uri)
puts "HTTP response: #{res.code}"
return res.body
rescue SystemCallError, Timeout::Error, Net::ProtocolError, IOError => e
puts "#{e.class.name}: #{e.message}"
retry if (try += 1) <= 3
raise e
end
end
end