89 lines
2.3 KiB
Ruby
89 lines
2.3 KiB
Ruby
|
|
# frozen_string_literal: true
|
||
|
|
|
||
|
|
require "csv"
|
||
|
|
require "net/http"
|
||
|
|
|
||
|
|
require "provider/adapters/adapter"
|
||
|
|
|
||
|
|
class Provider
|
||
|
|
module Adapters
|
||
|
|
class NB < Adapter
|
||
|
|
SDMX_URL = "https://data.norges-bank.no/api/data/EXR/B..NOK.SP"
|
||
|
|
class << self
|
||
|
|
def backfill_range = 365
|
||
|
|
end
|
||
|
|
|
||
|
|
def fetch(after: nil, upto: nil)
|
||
|
|
url = URI(SDMX_URL)
|
||
|
|
params = { format: "csvdata" }
|
||
|
|
params[:startPeriod] = after.to_s if after
|
||
|
|
params[:endPeriod] = upto.to_s if upto
|
||
|
|
url.query = URI.encode_www_form(params)
|
||
|
|
|
||
|
|
dataset = []
|
||
|
|
stream_csv(url) do |row|
|
||
|
|
record = parse_row(row)
|
||
|
|
dataset << record if record
|
||
|
|
end
|
||
|
|
|
||
|
|
dataset
|
||
|
|
end
|
||
|
|
|
||
|
|
def parse(csv)
|
||
|
|
CSV.parse(csv, headers: true, liberal_parsing: true).filter_map do |row|
|
||
|
|
parse_row(row)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
private
|
||
|
|
|
||
|
|
def parse_row(row)
|
||
|
|
return unless row["FREQ"] == "B"
|
||
|
|
|
||
|
|
base = row["BASE_CUR"]
|
||
|
|
return unless base
|
||
|
|
|
||
|
|
rate = Float(row["OBS_VALUE"])
|
||
|
|
unit_mult = Integer(row["UNIT_MULT"] || "0")
|
||
|
|
rate /= 10**unit_mult if unit_mult > 0
|
||
|
|
date = Date.parse(row["TIME_PERIOD"])
|
||
|
|
|
||
|
|
{ date:, base:, quote: "NOK", rate: }
|
||
|
|
end
|
||
|
|
|
||
|
|
def stream_csv(url)
|
||
|
|
uri = URI(url)
|
||
|
|
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
||
|
|
request = Net::HTTP::Get.new(uri)
|
||
|
|
http.request(request) do |response|
|
||
|
|
headers = nil
|
||
|
|
buffer = +""
|
||
|
|
|
||
|
|
response.read_body do |chunk|
|
||
|
|
buffer << chunk
|
||
|
|
while (line_end = buffer.index("\n"))
|
||
|
|
line = buffer.slice!(0..line_end)
|
||
|
|
if headers.nil?
|
||
|
|
headers = CSV.parse_line(line, liberal_parsing: true)
|
||
|
|
else
|
||
|
|
values = CSV.parse_line(line, liberal_parsing: true)
|
||
|
|
next unless values
|
||
|
|
|
||
|
|
row = CSV::Row.new(headers, values)
|
||
|
|
yield row
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
# Process remaining buffer
|
||
|
|
if headers && !buffer.empty?
|
||
|
|
values = CSV.parse_line(buffer, liberal_parsing: true)
|
||
|
|
yield CSV::Row.new(headers, values) if values
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|